57

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?

Mike
  • 43,847
  • 27
  • 105
  • 174
  • 1
    Possible duplicate of [Variably modified array at file scope](http://stackoverflow.com/questions/1712592/variably-modified-array-at-file-scope) – tstew Oct 06 '16 at 19:01

4 Answers4

81

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

That's why constants should be #defined:

#define a 6

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

zch
  • 14,551
  • 2
  • 40
  • 49
  • is a and b defined as int a = 6; int b = 3 instead of static int a = 6 works? –  Nov 30 '12 at 13:16
  • 1
    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. – zch Nov 30 '12 at 13:19
  • 1
    an alternative to macro is using anonymous enums, which are true integer constants `enum { a = 6, b = 3, };` – tstanisl Feb 22 '21 at 11:20
10

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

Detailed :

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

like this :

#define a 6
#define b 3

Or, follow c99 standard. and compile like for gcc.

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

The problem here is 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 for loop or any loop to fill the array.

For more info 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 array Hello it's in function
                            //scope but still error
return 0;
}


root@Omkant:~/c# clang -std=c99 vararr.c -o vararr
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 error as above.

But if you keep static as well as initialization the still will be error.

But if you remove 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 variable length array declaration 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 so making a and b as const won't help you but in C++ const will work fine.

Omkant
  • 8,730
  • 7
  • 37
  • 59
  • 1
    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. – WhozCraig Nov 30 '12 at 13:22
  • 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 Nov 30 '12 at 13:33
  • @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` – Omkant Nov 30 '12 at 13:36
  • @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 – Omkant Nov 30 '12 at 13:39
  • @WhozCraig : I got it ,YOu are wrong about stack- thing it could be global – Omkant Nov 30 '12 at 13:46
  • Please show me how, as I've tried in the past to have VLA's globally declared and every compiler I've ever used puked on them. Its definitely worth an up-vote if you would, please. – WhozCraig Nov 30 '12 at 13:48
  • @Omkant, you could add that the other kind of `integral constant expression`s that could be used here are enumeration constants. – Jens Gustedt Nov 30 '12 at 13:58
  • @WhozCraig : see my answer , and tell me agreed or not , http://ideone.com/f1AykV for correct , http://ideone.com/VV12D5 , for error.It's just a demo I did. – Omkant Nov 30 '12 at 14:00
  • @Omkant, you really worsened your answer with your edit. Neither the `[][]` nor with `static int Hello[a][b]` are valid C. – Jens Gustedt Nov 30 '12 at 14:02
  • what confuses me is why `static size_t const size` wouldn't work for the size of an array at file scope. It works in function scope even in C89, so I would expect an object that is constant and is known at compile and load time to be able to be used there. Unless `static` is the problem, which sucks because I would like to keep them tied to the one compilation module. – Braden Best May 22 '21 at 13:02
  • actually, this only happens if the array is a `static uint8_t[]`. The compiler has no problem doing it for `static char[]`. But then, when I try to set up a repl.it to demonstrate this (mind you, this was after having already demonstrated the error in an anonymous repl.it and copy/pasting the exact code from that repl.it into a named repl.it), it just compiles without issue. – Braden Best May 22 '21 at 13:11
  • I ran into this issue while I was writing a brainfuck VM in C, while creating the physical memory and assigning pointers into it for the program counter and virtual memory. – Braden Best May 22 '21 at 13:15
2

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.

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

See explanation in this thread:

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

Community
  • 1
  • 1
PolarBear2015
  • 565
  • 5
  • 12
  • 1
    The 'const' keyword in C does not really mean 'constant'. This misleads some users. – Low power Mar 12 '19 at 04:07
  • @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. – PolarBear2015 Aug 02 '19 at 23:44
1

Yea, this is annnoying:

const int len = 10;

int stuff[len];

Gives the error. I try to get away from doing #define x, because const int is a better way of declaring a constant, but then you have these cases where const int is not a true constant, even though the compiler knows full well it is.

Scott Franco
  • 393
  • 1
  • 12