Reputation: 5376
I tried to write a c program as below?
const int x = 5;
int main()
{
int arr[x] = {1, 2, 3, 4, 5};
}
This is giving warnings when I tried to compile with gcc as below.
simple.c:9: error: variable-sized object may not be initialized.
But the same is allowed in C++. When I pass x as array size, why x is not treated as constant?
Upvotes: 11
Views: 8940
Reputation: 11526
C23 is introducing constexpr
so the following should work:
static constexpr int x = 5;
int main()
{
int arr[x] = {1, 2, 3, 4, 5};
}
Upvotes: 1
Reputation: 158459
I think almost everyone has misunderstood the error, the error says:
variable-sized object may not be initialized.
which is correct, C99 and C11(although they are optional in C11). They can not be initialized in the declaration, we can see this from section 6.7.8
Initialization:
It is treated as a VLA because unlike C++, C expect an integer constnt expression:
If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type;
and an integer constant expression has the following restrictions:
shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.
which x
does not satisfy.
The type of the entity to be initialized shall be an array of unknown size or an object type that is not a variable length array type.
In C++ this is not a variable length array since x
is considered a constant expression and we can this is valid from the draft C++ standard section 8.3.4
Arrays under section 8
Declarators which says:
In a declaration T D where D has the form
D1 [ constant-expressionopt] attribute-specifier-seqopt
[...]If the constant-expression (5.19) is present, it shall be a converted constant expression of type std::size_t and its value shall be greater than zero. The constant expression specifies the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N elements numbered 0 to N-1[...]
If we removed the const from the declaration of x
it would fail for one of two reasons, either the compiler supports VLA as an extension and it would fail for the same reason it fails in C or the compiler does not support VLA as an extension and the therefore the declaration would not be valid.
Upvotes: 5
Reputation: 263217
In C const
doesn't mean "constant" (i.e., evaluable at compile time). It merely means read-only.
For example, within a function, this:
const int r = rand();
const time_t now = time(NULL);
is perfectly valid.
The name of an object defined as const int
is not a constant expression. That means that (in C prior to C99, and in all versions of C++) it can't be used to define the length of an array.
Although C99 (and, optionally, C11) support variable-length arrays (VLAs), they can't be initialized. In principle, the compiler doesn't know the size of a VLA when it's defined, so it can't check whether an initializer is valid. In your particular case, the compiler quite probably is able to figure it out, but the language rules are designed to cover the more general case.
C++ is nearly the same, but C++ has a special rule that C lacks: if an object is defined as const
, and its initialization is a constant expression, then the name of the object it itself a constant expression (at least for integral types).
There's no really good reason that C hasn't adopted this feature. In C, if you want a name constant of an integer type, 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 value of LEN
, you'll have to re-write the initializer.
Another approach is to use an anonymous enum
:
enum { LEN = 5 };
...
int arr[LEN] = {1, 2, 3, 4, 5};
The name of an enumeration constant is actually a constant expression. In C, for historical reasons, it's always of type int
; in C++ it's of the enumeration type. Unfortunately, this trick only works for constants of type int
, so it's restricted to values in the range from INT_MIN
to INT_MAX
.
Upvotes: 14
Reputation: 119069
When I pass x as array size, why x is not treated as constant?
Because in C, constant expressions can't involve the values of any variables, even const
ones. (This is one reason why C is so dependent on macro constants, whereas C++ would use const
variables for the same purpose.)
On the other hand, in C++, x
would certainly be a constant expression if x
is declared as const int x = 5;
.
If your question is why C++ is so much more liberal than C when it comes to constant expressions, I think it's to support metaprogramming, and allow complex computation to be performed at compile time using templates.
Upvotes: 6
Reputation: 1552
I will assume you are using a C99 compiler (which supports dynamically sized arrays). What happens is that the compiler can't know for sure in compilation time how your array will behave regarding memory.
Try this:
int arr[x];
memset( arr, 0, x*sizeof(int) );
and see if it works.
Another thing I think could be causing this is that const does not really mean anything under the hood, and so the compiler might not let you do what you are trying to because of that. You see, there are several ways you can alter const variables, and that is part of why c#, for example, does not present the const keyword. const is more like an alert for humans than anything else.
Upvotes: 1