9

I've looked at these and they do not answer my question:

variable-sized object may not be initialized

C compile error: "Variable-sized object may not be initialized"

Error: Variable-sized object may not be initialized. But why?


I am trying to write some fairly portable c code:

int main () 
{
    const int foo=13;
    int bar[foo]={0};
    return 0;
}

I get a `variable-sized object may not be initialized` error when compiling as `c` code using either:
  • gcc 4.3.4
  • arm-linux-gnueabi-gcc 4.4.5

And if i compile it as c in VS2008 i get a slightly different error C2057: expected constant expression


I understand that here, the c code compiler is not recognising const int foo=13; to be truly constant; for example we might have

void a(int fool) 
{    
    const int foo=fool;
    int bar[foo]={0};
}


I also realise that unlike the gcc compilers, the VS2008 compiler has no concept of C99 variable-length arrays. And that MS apparently has not mentioned any future support.


And yet, cpp code compilation with either gcc or MS compilers is altogether different/cleverer ?!


And also *what i do not understand* regarding the **gcc** `c` code compiler is:
  • since this code does compile,
int main () 
{
    int bar[13]={0};
    return 0;
}
  • why this code does not compile..
int main()
{
    const int foo=13; //cpp compiler knows this really is const ! 
    int bar[foo]={0};
    return 0;
}
  • and yet this code does compile?
int main()
{
    const int foo=13;  
    int bar[foo+1]={0}; //wtF?
    return 0;
}


(NB: in this last case, MS c code compilation fails; consistently as with int bar[foo]={0};)

S.B
  • 13,077
  • 10
  • 22
  • 49
violet313
  • 1,912
  • 1
  • 15
  • 19
  • On my TDM-GCC 4.6.1 the last example does **not** compile (again with "variable-sized object may not be initialized"). I also never heard of VLAs beeing initialized by an initializer list, is this even correct C? Looking into it.. – Anthales Apr 12 '12 at 18:29
  • For the part of your question on MS compilers this is not the only feature that is missing, they simply don't support C99. Since last year there is even a newer version of the standard, C11, so they now lack 2 major versions behind. – Jens Gustedt Apr 12 '12 at 18:45
  • ..well i agree with you about the VLA initialisation question -which is why i threw in the `cpp` compilation tests. – violet313 Apr 12 '12 at 18:54
  • 1
    It's never a good idea to trying to understand a C question by looking at what the C++ compiler does - as far as I know C++ doesn't even have VLAs, but this is only a GNU extension from gcc. If you really need to know if you are writing legal C code, pick up your C standard [here](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf). And now accept Mats answer already ;) – Anthales Apr 12 '12 at 18:59

3 Answers3

13

C99 §6.7.8 Initialization says this:

The type of the entity to be initialized shall be an array of unknown size or an object type that is not a variable length array type.

So your initialization is invalid C.

The only way for type a[size] to not be a VLA is for size to be an integer constant expression (§6.7.5.2). What you have there is not an integer constant expression, so you have a VLA:

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 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.

Part §6.6/6 Constant expressions defines them as:

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, 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 operator.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • Ok. So `foo+1` cannot be an integer constant expression, since at compilation time it is not possible to certainly know the value of `foo` even if it's declared as `const`. So it's a bug in my gcc. – violet313 Apr 12 '12 at 19:10
  • 1
    Interestingly enough, `clang` supports `foo+1` as an extension: http://clang.llvm.org/docs/UsersManual.html#c_ext – Mat Apr 12 '12 at 19:20
  • It's still nagging me why in http://ideone.com/Br6cC, array `bar` is being treated as a VLA. since it can be determined at compilation time that `foo` is indeed an integer constant. infact i'm inclinded to find out what kind of assembly code actually gets generated for something like `const int foo=13;` – violet313 Apr 12 '12 at 19:55
  • It doesn't matter if the compiler can determine whether it is a compile-time constant or not, the standard mandates an integer constant expression, and a `const int` value isn't one. (C++ has more complex rules with `constexpr`, but doesn't have VLAs I believe.) – Mat Apr 12 '12 at 20:11
1

Actually, for my gcc (version 4.4.4), your last example

int main()
{
    const int foo=13;  
    int bar[foo+1]={0}; //wtF?
    return 0;
}

also does not compile, just as one would expect. You might want to double-check your toolchain (to verify you didn't relink an existing '.o' in there somewhere), and try again.

If you find that it really does work, here is my gcc -v output, perhaps you can detect a difference in the configuration and that might lend some light.

Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.4 20100630 (Red Hat 4.4.4-10) (GCC) 
Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • well i get [this](http://pastebin.com/5TKnuStM) ~not really sure what should i be looking for tbh -looks like i may be falling foul of another *debian squeeze stable* effect – violet313 Apr 12 '12 at 18:45
  • i still don't really undestand why `cpp` works but `c` does not. i mean i can see that the `cpp` compiler has all the info necessary to not throw an error. but is there some c-standard for specifically *not behaving the same way? – violet313 Apr 12 '12 at 18:50
  • @violet313, My posting was that `cpp` _does not_ work. Apparently you are using a different compiler, or even just a different configured copy of `cpp`. The one you are using isn't working correctly if it allowed you to compile; it is a bug in that compiler (and if you care about portability, you shouldn't use such a construct even if you compiler allowed it). – Edwin Buck Apr 12 '12 at 19:02
  • [Edwin](http://stackoverflow.com/users/302139/edwin-buck). yes i do care about portability. i fixed my code with a #define -curiosity drove me here. +1 for your time – violet313 Apr 12 '12 at 19:18
  • while i do agree with [anthales](http://stackoverflow.com/users/1250595/anthales) that `c` & `cpp` are different beasts & you say that for you the `cpp` compilation does not work, i also have [this code](http://ideone.com/ylJ6R) `cpp` compiling under **VS2008**. & note **MS** does *not do VLAs ;) – violet313 Apr 12 '12 at 21:23
  • @violet313 it doesn't matter if they do VLAs or not, as the construct between the array brackets is not a VLA. While it might not make much sense, a `const int` cannot be combined with anything to make an `integer constant expression`. Even though you can't reassign the variable's value, the value contains a variable reference, so it isn't an `integer constant expression`. – Edwin Buck Apr 12 '12 at 21:43
  • yes. i think i had two issues: the standard (sorry Mat i sometimes suffer from tldr-itis) vs the implementation; &that i ever hit this in the first place, which seems to be a feature of *my gcc. both are now essentially resolved for me. thx all! – violet313 Apr 12 '12 at 21:59
-1

As Matt has already quoted the standard, const qualifier applied to an integer variable does not count as an integer constant expression. We might wonder why? It looks as innocent as an integer constant!

This may be because const are not absolutely consts. You might alter their values through pointers and all a compiler might do, if at all it catches such an assignment , is throw a warning but cant really prevent you from altering the const value.

PS: Don't trust the online compilers like ideone.com etc. Here's one silly runtime error it throws for a very simple C program.

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
  • ha. fair point but i did originally hit the problem & then compile the tests on my *debian squeeze* -& then found that the ideone compiler did the same thing -which seemed both convenient & seemed to make the question more relevant – violet313 Apr 12 '12 at 18:58