3

This compiles fine under C99

const int DIM;

int main() {
    int tab[DIM];
}

while the following gives the error

int tab[DIM];

int main() {
}

error: variably modified tab at file scope

Why?

I know how to fix it :

#define DIM  10

But this does not provide the answer to my question Thanks for your reply

7
  • 1
    In the 2 snippets I forgot to initialize DIM ``` const int DIM=10; ``` Commented Nov 27, 2024 at 20:41
  • If you found a solution, please consider answering your own question. Commented Nov 27, 2024 at 20:45
  • 1
    Quite simply, in the second block of code, DIM within the definition of the "int tab[DIM];" statement is not defined at any point, so the compiler is going to throw an error. That is why to make the program compile you need "DIM" defined as you note, or you would need a statement like "int DIM = 10" before your "int tab[DIM]" statement. Commented Nov 27, 2024 at 20:45
  • I did add const int DIM=10; in both snippets. I keep getteing the error : error: variably modified tab at file scope in the 2nd snippent Commented Nov 27, 2024 at 20:50
  • 1
    @chux: C23 does indeed offer an alternative: constexpr int DIM = 10; int tab[DIM]; is OK at global scope. Commented Nov 28, 2024 at 7:29

2 Answers 2

2

Sizes of variable length arrays are calculated at run-time.

Read for example the following quote from the C 2024 Standard (6.5.4.5 The sizeof and alignof operators):

The sizeof operator yields the size (in bytes) of its operand, which can be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

or (6.7.7.3 Array declarators):

If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.

Pay attention to that variables declared at file scope have static storage duration.

By the way in the first program you shall initialize the variable DIM because it has the qualifier const and in the second program you missed its definition.:)

In C variables declared with the qualifier const are not constant expressions that are evaluated at compile time.

Thus the first progam is compiled successfully because the declared array has automatic storage duration. Memory for the array is allocated at run time.

The second program is not compiled because the declared at file scope variable length array has static storage duration.

If you will include the directive

#define DIM  10

then the declared array will not be a variable length array because its size is specified with a constant expression that is evaluated at compile time.

Sign up to request clarification or add additional context in comments.

4 Comments

Do not cite text from the C standard drafts as text from the official standard. Both what was said to be the “final working draft,” N3054, and some later draft, N3096, differ considerably from the published standard, including the insertion of addition subclauses, making the clause numbering different between the drafts and the official standard. After a committee does its work, there is some additional balloting process that may result in changes to a standard before publication. Also, you had text cited from the standard that did not appear in the drafts or the standard.
@EricPostpischil I cited N3088. In any case nothing was changed relative to variable length arrays in the provided quites.
You may have quoted from draft N3088, but you cited the standard. That is the wrong thing to do. When quoting material, you should state the actual source it came from. That means, if it is from a draft, then saying it is from a draft, and which number, or, if it is from the official standard, then saying it is from the standard. The clause numbers changed, one word changed, and you had additional words in the quote that were apparently your own, not in the draft or the standard.
@EricPostpischil TMaybe I made a typo when combined the quotes and my text.
2

Defining an array at the global scope using

const int DIM = 10;
int tab[DIM];

Is not allowed in C (but is supported in c++) because the array dimensions for objects defined at global scope (and local scope with global storage class specified by the static keyword) must be an integer constant expression. Integer constant expressions cannot be computed using the value of const variables as specified in the C Standard (before C23):

6.6 Constant expressions

Constraints
3 Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.
4 Each constant expression shall evaluate to a constant that is in the range of representable values for its type.
8 An integer constant expression shall have integer type and shall only have operands that are integer constants, named and compound literal constants of integer type, character constants, sizeof expressions whose results are integer constants, alignof expressions, and floating, named, or compound literal constants of arithmetic type 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 typeof operators, sizeof operator, or alignof operator.

Defining tab as a local array in the main function with automatic storage is allowed since C99 and creates a variable length array (VLA) whose length is computed at run time by evaluating the expression, and is constant for the life time of the object. Note however these limitations:

  • the length must not be 0 (so the code in the question invokes undefined behavior if DIM is not initialized).
  • if the length exceeds available stack space space at the point of definition, undefined behavior is invoked (and probably results in a stack overflow).
  • such arrays cannot be initialized with an initializer.

There are other ways to express the array length with an identifier:

#define DIM 10
int tab[DIM];

or

enum { DIM = 10 };
int tab[DIM];

The latest version of the C Standard added the constexpr storage class which allows variables to be used in integer constant expressions. Recent compiler versions (gcc version 13 or clang version 19) with -std=c23, support this version:

constexpr int DIM = 10;
int tab[DIM];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.