Simon Elliott
Simon Elliott

Reputation: 2117

What are the implications of using static const instead of #define?

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 ofx' 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?

Upvotes: 11

Views: 3819

Answers (5)

Walt Sellers
Walt Sellers

Reputation: 3939

Because you declared x as 'static' that makes it a global variable. Its just known only to the main() function in which it is declared. By declaring YY outside of any function, you have made it global. 'static' also makes it a global, but known only to this file.

If you declared YY as just 'const int YY = 1024', the compiler might treat it like a #define, but with a type. That depends on the compiler.

At this point 2 things might be wrong.

1:

All globals are initialized at runtime, before main() is called.

Since both x and YY are globals, they are both initialized then.

So, the runtime initialization of global x will have to allocate space according to the value in YY. If the compiler is not treating YY like #define with a type, it has to make a compile-time judgement about runtime values. It may be assuming the largest possible value for an int, which really would be too big. (Or possibly negative since you left it signed.)

It may be interesting to see what happens if you only change YY to a short, preferably an unsigned short. Then its max would be 64K.

2:

The size of global space may be limited on your system. You didn't specify the target platform and OS, but some have only so much.

Since you declared x as size YY, you have set it to take YY chars from global space. Every char in it would essentially be a global. If the global space on your system is limited, then 1024 chars of it may be too much.

If you declared x as a pointer to char, then it would take sizeof(char*) bytes. (4 bytes is the size of a pointer on most systems.) With this, you would need to set the pointer to the address of properly malloc'd space.

By declaring x without 'static', it becomes a local variable and is only initialized once the owning function is executed. And its space is taken from the stack, not global space. (This can still be a problem for systems or threads with very limited stack.) YY's value has long since been set by this point, so there is no problem.

Also:

I don't recall if there is any guarantee that globals are initialized in any order. If not, then x could be initialized before YY. If that happened then YY would just contain the random contents of RAM.

Upvotes: 1

jbishop
jbishop

Reputation:

/* 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];
};

Upvotes: 0

Steve Melnikoff
Steve Melnikoff

Reputation: 2670

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];
}

Upvotes: 0

sambowry
sambowry

Reputation: 2476

You may use 'enum' or 'define' to declare the size:

#define          XX   1024 
static int const YY = 1024;
           enum{ ZZ = 1024 };

extern int main(void){

  static char x[XX]; // no error
  *(int*)&XX = 123;  // error: lvalue required as unary ‘&’ operand


  static char y[YY]; // error: storage size of ‘y’ isn’t constant
  *(int*)&YY = 123;  // no error, the value of a const may change


  static char z[ZZ]; // no error
  *(int*)&ZZ = 123;  // error: lvalue required as unary ‘&’ operand
}

Upvotes: 12

Martin B
Martin B

Reputation: 24140

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.

Upvotes: 14

Related Questions