69

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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 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
  • 1
    @tstew: No, that is for Objective-C – Peter Mortensen Jul 29 '23 at 09:00
  • Related: *["static const" vs "#define" vs "enum"](https://stackoverflow.com/questions/1674032)* and *[static const vs #define](https://stackoverflow.com/questions/1637332/)* – Peter Mortensen Jul 29 '23 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. – Toby Speight Jul 29 '23 at 11:55
  • Note: The title is partly literal and *"variably"* is part of the (literal) error message. [E.g.](https://stackoverflow.com/questions/19881918/error-with-c-code), *"`variably modified ‘child’ at file scope`"* – Peter Mortensen Aug 13 '23 at 18:54
  • @PeterMortensen The technically correct and formal term is _Variable length array_. I don't really see why we can't use the most correct term, especially if this post is to be used as canonical dupe. – Lundin Aug 14 '23 at 14:24
  • @Lundin: We can. I don't have any objections. It was just to explain the origin of the weird word "variably". – Peter Mortensen Aug 19 '23 at 18:40

4 Answers4

95

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zch
  • 14,931
  • 2
  • 41
  • 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
  • 3
    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
  • 5
    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
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Omkant
  • 9,018
  • 8
  • 39
  • 59
  • 2
    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
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

PolarBear2015
  • 745
  • 6
  • 14
  • 3
    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
    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 Aug 14 '23 at 14:21
  • 1
    @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. – PolarBear2015 Aug 24 '23 at 18:33
  • 1
    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. – Lundin Aug 25 '23 at 08:27
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 } };
toyota Supra
  • 3,181
  • 4
  • 15
  • 19