pm100
pm100

Reputation: 50210

Why is const int x = 5; not a constant expression in C?

I thought C had no more surprises for me, but this surprised me.

    const int NUM_FOO = 5;
    ....

    int foo[NUM_FOO];
==>error C2057: expected constant expression

My C++ experience has made me internally deprecate #define as much as possible. So this one was a real surprise. VS2019, compiled with /TC. I thought C99 allowed variable size arrays anyway.

  1. Can anybody explain why the rejection occurs, since the compiler for sure knows at compile time the size of the array?

  2. Is it not the case that C99 allows variable size arrays?

Upvotes: 5

Views: 3246

Answers (4)

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215497

On top of the existing answers which are all good, the reason a const-qualified object fundamentally can't in general be a constant expression, in the sense of "one that can be evaluated at compile time" (as mentioned in Keith's answer), is that it can have external linkage. For example, you can have in foo.c

const int NUM_FOO = 5;

and in bar.c:

extern int NUM_FOO;
...
int foo[NUM_FOO];

In this example, the value of NUM_FOO cannot be known when compiling bar.c; it is not known until you choose to link foo.o and bar.o.

C's model of "constant expression" is closely tied to properties that allow translation units (source files) to be translated (compiled) independently to a form that requires no further high-level transformations to link. This is also why you can't use addresses in constant expressions except for address constant expressions which are limited to essentially the address of an object plus a constant.

Upvotes: 2

Keith Thompson
Keith Thompson

Reputation: 263557

In C, this declaration:

const int NUM_FOO = 5;

doesn't make NUM_FOO a constant expression.

The thing to remember (and yes, this is a bit counterintuitive) is that const doesn't mean constant. A constant expression is, roughly, one that can be evaluated at compile time (like 2+2 or 42). The const type qualifier, even though its name is obviously derived from the English word "constant", really means "read-only".

Consider, for example, that these are a perfectly valid declarations:

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

The const just means that you can't modify the value of r or now after they've been initialized. Those values clearly cannot be determined until execution time.

(C++ has different rules. It does make NUM_FOO a constant expression, and a later version of the language added constexpr for that purpose. C++ is not C.)

As for variable length arrays, yes, C added them in C99 (and made them optional in C11). But as jamesdlin's answer pointed out, VS2019 doesn't support C99 or C11.

(C++ doesn't support VLAs. This: const int NUM_FOO = 5; int foo[NUM_FOO]; is legal in both C99 and C++, but for different reasons.)

If you want to define a named constant of type int, you can use an enum:

enum { NUM_FOO = 5 };

or an old-fashioned macro (which isn't restricted to type int):

#define NUM_FOO 5

jamesdlin's answer and dbush's answer are both correct. I'm just adding a bit more context.

Upvotes: 9

dbush
dbush

Reputation: 224522

A variable with the const qualifier does not qualify as a constant expression.

Section 6.6p6 of the C11 standard regarding Constant Expressions states

An integer constant expression shall have integer type and shall only have operands that are integer constants,
enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, 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 or _Alignof operator

Note that const qualified integer objects are not included.

This means that int foo[NUM_FOO]; is a variable length array, defined as follows from section 6.7.6.2p4:

If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations or type names with function prototype scope; such arrays are nonetheless complete types. 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; otherwise, the array type is a variable length array type.

As for the error you're getting, that is because Visual Studio is not fully compliant with C99 and does not support variable length arrays.

Upvotes: 3

jamesdlin
jamesdlin

Reputation: 90135

  1. const in C does not declare a compile-time constant. You can use an enum constant instead if you want to avoid using #define and want a symbolic name that can appear in a debugger.

  2. C99 does support VLAs. However, VS2019 does not support C99.

Upvotes: 2

Related Questions