Why is the size of the array as a constant variable unacceptable in C, but allowed in C ++?

I tried to write a c program as shown below?

const int x = 5; int main() { int arr[x] = {1, 2, 3, 4, 5}; } 

This gives warnings when I tried to compile gcc, as shown below.

simple.c: 9: error: a variable-sized object cannot be initialized.

But the same thing is allowed in C ++. When I pass x as the size of the array, why is x not considered as a constant?

+6
source share
4 answers

In C, const does not mean "constant" (that is, evaluated at compile time). It just means read only.

For example, inside a function, this is:

 const int r = rand(); const time_t now = time(NULL); 

excellent.

The name of an object defined as const int is not a constant expression. This means that (in C to C99 and in all versions of C ++) it cannot be used to determine the length of an array.

Although C99 (and, optionally, C11) support variable length arrays (VLAs), they cannot be initialized. Basically, the compiler does not know the size of the VLA when it is defined, so it cannot check if the initializer is valid. In your particular case, the compiler is most likely able to understand this, but the rules of the language are intended to cover a more general case.

C ++ is almost the same, but C ++ has a special rule that C does not have: if an object is defined as const , and its initialization is a constant expression, then the name of the object itself is a constant expression (at least for integral types) .

There is really no good reason that C did not use this function. In C, if you want an integer type name constant, the usual approach is to use a macro:

  #define LEN 5 ... int arr[LEN] = {1, 2, 3, 4, 5}; 

Note that if you change the LEN value, you will have to overwrite the initializer.

Another approach is to use an anonymous enum :

  enum { LEN = 5 }; ... int arr[LEN] = {1, 2, 3, 4, 5}; 

The name of the enumeration constant is actually a constant expression. In C, for historical reasons, it is always of type int ; in C ++, this is an enum type. Unfortunately, this trick only works for constants of type int , so it is limited to values ​​ranging from INT_MIN to INT_MAX .

+10
source

When I pass x as the size of the array, why is x not considered as a constant?

Because in C, constant expressions cannot include the values ​​of any variables, even const units. (This is one of the reasons why C is so dependent on macro const , while C ++ will use const variables for the same purpose.)

In C ++, on the other hand, x will certainly be a constant expression if x declared as const int x = 5; .

If your question is why C ++ is much more liberal than C when it comes to constant expressions, I think it supports metaprogramming and allows complex calculations at compile time using templates.

+4
source

I think that almost everyone misunderstood the error, the error says:

a variable-sized object cannot be initialized.

which is correct, C99 and C11 (although they are optional in C11). They cannot be initialized in the declaration, we can see this from section 6.7.8 Initialization:

It is considered as a VLA, because unlike C ++, C expects an integer expression constnt:

If the size is an integer constant expression, and the element type has a known constant size, the array type is not an array of variable length;

and the integer constant expression has the following limitations:

must have an integer type and should only have operands that are integer constants, enumeration constants, character constants, sizeof expressions, the results of which are integer constants and floating constants, which are the direct operands of castings. Translation operators in integer constant expression must convert arithmetic types to integer types, except that part of the operand is for sizeof operator.

which x does not satisfy.

The type of the object to be initialized must be an array of unknown size or an object type that is not an array of variable length.

In C ++, this is not a variable-length array, since x is considered a constant expression, and we can do this from the standard section of a C ++ 8.3.4 project. Arrays in section 8 Declarators, which states:

In the declaration of TD, where D has the form

  D1 [ constant-expressionopt] attribute-specifier-seqopt 

[...] If the constant expression (5.19) is present, it must be a converted constant expression of the type std :: size_t and its value must be greater than zero. The constant expression defines the boundary (number of elements in) of the array. If the value of the constant expression is N, the array has N elements from 0 to N-1 [...]

If we remove const from declaration x , it will fail for one of two reasons, either the compiler supports VLA as an extension, and it fails for the same reason as a failure in C, or the compiler does not support VLA as an extension, and therefore declaration is not valid.

+3
source

I assume that you are using the C99 compiler (which supports arrays with dynamic size). What happens is that the compiler cannot know exactly at compile time how your array will behave relative to memory.

Try the following:

 int arr[x]; memset( arr, 0, x*sizeof(int) ); 

and see if it works.

Another thing that, in my opinion, may be the reason for this, is that const does not mean anything under the hood, and therefore the compiler may not allow you to do what you are trying to do because of this. You see, there are several ways to change constant variables, and this is part of why C #, for example, does not represent the const keyword. const is more like a warning to people than anything else.

0
source

Source: https://habr.com/ru/post/975458/


All Articles