tags:

views:

583

answers:

4

gcc complains about this:

#include <stdio.h>
static const int YY = 1024;
extern int main(int argc, char*argv[])
{  
  static char x[YY];
}

$ gcc -c test1.c test1.c: In function main': test1.c:5: error: storage size of x' isn't constant test1.c:5: error: size of variable `x' is too large

Remove the “static” from the definition of x and all is well.

I'm not exactly clear what's going on here: surely YY is constant?

I had always assumed that the "static const" approach was preferable to "#define". Is there any way of using "static const" in this situation?

+9  A: 

In C, a const variable isn't a "real" compile-time constant... it's really just a normal variable that you're not allowed to modify. Because of this, you can't use a const int variable to specify the size of an array.

Now, gcc has an extension that allows you to specify the size of an array at runtime if the array is created on the stack. This is why, when you leave off the static from the definition of x, the code compiles. However, this would still not be legal in standard C.

The solution: Use a #define.

Edit: Note that this is a point in which C and C++ differ. In C++, a const int is a real compile-time constant and can be used to specify the size of arrays and the like.

Martin B
I'd like to comment out that `g++` does compile the code.
Pavel Shved
That's correct... in C++, `const` produces a "real" compile-time constant. I'll edit the answer to point out this distinction.
Martin B
C99 allows variable-length arrays (VLAs) on the stack. It's not limited just to gcc.
Loadmaster
+9  A: 
sambowry
enum here is rather ugly, though. It thwarts enum's meaning completely.
Metiu
Very ugly, but it works, and has fewer side affects than #define. It's the C equivalent of the C++ "const int foo = 1024;".
David Thornley
@Metiu: Why would using enum be considered any uglier than #define?
Michael Burr
@sambowry: your comment "the value of a const may change" is not quite correct. The syntax of that statement is fine, since `YY` is an lvalue; however, the sematics are not. Changing an actual const object results in undefined behavior (but changing a non-const object through a re-cast const pointer or reference is OK).
Michael Burr
Since an enum is just an int constant with a name, it seems to me that it is appropriate to use in this situtation. Just be sure to give it a good name, like NAME_SIZE.
Loadmaster
A: 

To follow on from Martin B's answer, you could do this:

#include <stdio.h>

#define XSIZE 1024

static const int YY = XSIZE;

int main(int argc, char*argv[])
{  
    static char x[XSIZE];
}
Steve Melnikoff
A: 
/* SHOULDN'T THIS WORK IN C++? */
// .h

class C {
public:
   static const int kSIZE;
   int a[kSIZE]; // error: array bound is not an integer constant
};


// .cc

const int C::kSIZE = 1;


/*  WORKS FINE */    
// .h

class C {
public:
   enum eCONST { kSIZE = 1 };
   int a[kSIZE];
};
jbishop
Just call it a `const int` instead of a `static const int`, and you'll be fine. The problem with the `static const int` is that `C::kSIZE` is initialized in the `.cc` file -- so how should a different `.cc` (which sees only the header file) know what `sizeof(C)` is?
Martin B
aha... ok cool. seems a bit silly to have another 4 bytes per object just for the constant though... seems that the static const should be able to be initialized in the header. thank you!
jbishop