82

I have some code like this:

static int a = 6;
static int b = 3;

static int Hello[a][b] =
{
    { 1,2,3},
    { 1,2,3},
    { 1,2,3},
    { 1,2,3},
    { 1,2,3},
    { 1,2,3}
};

But when I compile it, it says error:

variably modified 'Hello' at file scope

How could this happen? And how could I fix it?

7
  • 2
    Possible duplicate of Variably modified array at file scope Commented Oct 6, 2016 at 19:01
  • 2
    @tstew: No, that is for Objective-C Commented Jul 29, 2023 at 9:00
  • Related: "static const" vs "#define" vs "enum" and static const vs #define Commented Jul 29, 2023 at 11:23
  • 1
    @PeterMortensen (and others) - I've flagged a few questions as duplicates of this (I think they should all appear as Linked in the right-hand column). It would be great if you could browse them and close-vote the ones I'm right about. Commented Jul 29, 2023 at 11:55
  • Note: The title is partly literal and "variably" is part of the (literal) error message. E.g., "variably modified ‘child’ at file scope" Commented Aug 13, 2023 at 18:54

4 Answers 4

108

You can not have a static array whose size is given as a variable.

That's why constants should be #defined:

#define a 6

This way, the preprocessor will replace a with 6, making it a valid declaration.

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

3 Comments

is a and b defined as int a = 6; int b = 3 instead of static int a = 6 works?
No, this will still be a variable. Use #define. In C++ there is const that would allow const int a = 6; to work, but even const is not enough in C.
an alternative to macro is using anonymous enums, which are true integer constants enum { a = 6, b = 3, };
11

Simple answer: A variable modified array at file scope is not possible.

Detailed:

Make it a compile time integral constant expression, since the array length must be specified at the compile time.

Like this:

#define a 6
#define b 3

Or, follow the C99 standard. and compile like for GCC.

gcc -Wall -std=c99 test.c -o test.out

The problem here is a variable-length array with providing length may not be initialized, so you are getting this error.

Simply

static int a = 6;
static int b = 3;

void any_func()
{
    int Hello [a][b]; // No need of initialization. No static array means no file scope.
}

Now use a for loop or any loop to fill the array.

For more information, just a demo:

#include <stdio.h>

static int a = 6;
int main()
{
    int Hello[a] = {1, 2, 3, 4, 5, 6}; // See here initialization of the array 'Hello'. It's in the function
                                       // Scope, but still an error
    return 0;
}

Compile

cd ~/c
clang -std=c99 vararr.c -o vararr

Output:

vararr.c:8:11: error: variable-sized object may not be initialized
int Hello[a]={1,2,3,4,5,6};
          ^
1 error generated.

If you remove static and provide initialization then it will generate the error as above.

But if you keep static as well as initialization then it will still be an error.

But if you remove the initialization and keep static, the below error will come.

error: variable length array declaration not allowed at file scope
static int Hello[a];
           ^     ~
1 error generated.

So a variable-length array declaration is not allowed at file scope, so make it function or block scope inside any function (but remember making it function scope must remove initialization)

Note: Since it's C tagged, making a and b as const won't help you, but in C++ const will work fine.

12 Comments

C99 doesn't support VLA's at file-scope either. it must be at function-scope or smaller. He 'can' use const index declarations, including static const int a = 10; for example, at file scope.
Its a stack-thing. If they're even supported by your C99 compiler, it isn't mandated that they be; the standard defines how they behave if your C99 does support them. The implementations use stack-math to implement them. You can't do that at global (or file) data-segment compilation level.
@WhozCraig: But when I define a in main in that case also it's not working, compiling with -std=c99 . now a is on stack so what's the problem now , I have tried with gcc and clang
@WhozCraig: I read somewhere on SO itself so posted the answer , but I am now myself facing this with -std=c99 and not compiling, any clue ? going to edit my answer also
@WhozCraig : I got it ,YOu are wrong about stack- thing it could be global
|
4

When using Clang/LLVM, the following works:

static const int a = 6;
static const int b = 3;

static int Hello[a][b] =
{
    {1, 2, 3},
    {1, 2, 3},
    {1, 2, 3},
    {1, 2, 3},
    {1, 2, 3},
    {1, 2, 3}
};

(To see it in the generated assembly, one needs to use 'Hello', so it will not be optimized out.)

However, this will generate an error if C99 mode is selected (-std=c99). It will only generate a warning (Wgnu-folding-constant) if -pedantic is selected.

=== EDIT === Clang now (version 14.0.0) generates this warning as default: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant]

GCC does not seem to allow this (const is interpreted as read-only).

See the explanation in this question:

"Initializer element is not constant" error for no reason in Linux GCC, compiling C

5 Comments

The 'const' keyword in C does not really mean 'constant'. This misleads some users.
@Lowpower I agree - this is a detail of the implementation. Moreover the actual implementation of cost seems to vary, in C++ at least some const are no longer 'read only variable (meaning there is no symbol in the symbol table pointing to read-only memory segment) but true constants resolved at compile-time.
Neither clang nor gcc allows this to compile cleanly, because it is invalid C and a non-standard compiler extension. Notably a program could "just have warnings" and still be invalid C.
@Lundin This apparently changed (which is good) since I wrote the answer, Clang now generates the warning: "variable length array folded to constant array as an extension" (-Wgnu-folding-constant) by default. The code is still "valid" - if that means accepted by the compiler and works s expected (like all extensions) but is not standard.
If something goes against a constraint or syntax rule in the standard, then it is invalid C - it is not C but something else - "C with extensions". Compiler extensions might often violate constraints/syntax, but doing so will leave the compiler non-conforming unless it gives a warning.
0

The dimensions of the array must be constant expressions and your friend 'compiler' must be informed about that. So tell to compiler that a and b are constant values.

static constexpr int a = 6;

static constexpr int b = 3;

static int Hello[a][b] = { { 1,2,3 }, { 1,2,3 }, { 1,2,3 }, { 1,2,3 }, { 1,2,3 }, { 1,2,3 } };

1 Comment

Use 'const' for older C/ C++

Your Answer

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