2009-09-25 12 views
11

gcc se queja de esto:¿Cuáles son las implicaciones de usar const estático en lugar de #define?

#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: En función main': test1.c:5: error: storage size of x 'no es constante test1.c: 5: Error: el tamaño de la variable `x' es demasiado grande

Retire la “estática” de la definición de X y todo está bien.

No estoy del todo claro qué está pasando aquí: seguramente YY es constante?

siempre había asumido que el enfoque "static const" era preferible a "#define". ¿Hay alguna forma de usar "const estático" en esta situación?

+0

La variable es realmente * no * creada en la pila en virtud de 'static' en' static char x [YY] ' – Dirk

Respuesta

14

En C, una variable const no es una constante de tiempo de compilación "real" ... no deja de ser una variable normal que no está permitido modificar. Debido a esto, no puede usar una variable const int para especificar el tamaño de una matriz.

Ahora, gcc tiene una extensión que le permite especificar el tamaño de una matriz en tiempo de ejecución si la matriz se crea en la pila. Es por esto que, cuando deja el static de la definición de x, el código se compila. Sin embargo, esto todavía no sería legal en C estándar

La solución: Utilice una #define.

Editar: Tenga en cuenta que este es un punto en el que C y C++ difieren. En C++, un const intes una constante de tiempo de compilación real y se puede utilizar para especificar el tamaño de matrices y similares.

+0

Me gustaría comentar que' g ​​++ 'compila el código. –

+0

Eso es correcto ... en C++, 'const' produce una constante de tiempo de compilación" real ". Editaré la respuesta para señalar esta distinción. –

+2

C99 permite matrices de longitud variable (VLA) en la pila. No está limitado solo a gcc. –

12

Es posible utilizar 'enumeración' o 'definir' para declarar el tamaño:

#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 
} 
+0

enum aquí es bastante feo, sin embargo. Impide completamente el significado de enum. – Metiu

+2

Muy feo, pero funciona y tiene menos efectos secundarios que #define. Es el equivalente en C de C++ "const int foo = 1024;". –

+1

@Metiu: ¿Por qué usar enum se consideraría más feo que #define? –

0

Para una continuación de la respuesta de Martin B, usted puede hacer esto:

#include <stdio.h> 

#define XSIZE 1024 

static const int YY = XSIZE; 

int main(int argc, char*argv[]) 
{ 
    static char x[XSIZE]; 
} 
0
/* 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]; 
}; 
+0

Simplemente llámalo 'const int' en lugar de' static const int', y estarás bien. El problema con 'static const int' es que' C :: kSIZE' se inicializa en el archivo '.cc', así que ¿cómo debería saber un' .cc' diferente (que solo ve el archivo de encabezado) 'sizeof (C) '¿es? –

+0

aha ... ok genial. Parece un poco tonto tener otros 4 bytes por objeto solo para la constante ... parece que la constante estática debería poder inicializarse en el encabezado. ¡gracias! –

1

Debido usted declaró x como 'estático' que lo convierte en una variable global. Es conocido solo por la función main() en la que se declara. Al declarar YY fuera de cualquier función, la ha hecho global. 'static' también lo convierte en global, pero solo conocido por este archivo.

Si usted declaró YY tan solo 'const int YY = 1024', el compilador podría tratarlo como un #define, pero con un tipo. Eso depende del compilador.

En este punto 2 cosas podrían estar mal.

1:

Todos globales se inicializan en tiempo de ejecución, antes de main() se llama.

Dado que tanto x como YY son globales, ambos se inicializan entonces.

Por lo tanto, el tiempo de ejecución de inicialización x globales tendrá que asignar espacio en función del valor de AA. Si el compilador no trata YY como #define con un tipo, tiene que hacer un juicio en tiempo de compilación sobre los valores de tiempo de ejecución.Puede suponer el mayor valor posible para un int, que realmente sería demasiado grande. (O posiblemente negativo ya que lo dejó firmado.)

Puede ser interesante ver qué sucede si solo cambia YY a un corto, preferiblemente un corto sin firmar. Entonces su máximo sería 64K.

2:

El tamaño del espacio global puede ser limitado en su sistema. No especificó la plataforma de destino y el sistema operativo, pero algunos tienen solo mucho.

Como ha declarado x como el tamaño YY, lo ha configurado para que tome los caracteres YY del espacio global. Cada char en ella sería esencialmente un global. Si el espacio global en su sistema es limitado, entonces 1024 caracteres pueden ser demasiado.

Si declaró x como un puntero a char, tomaría sizeof (char *) bytes. (4 bytes es el tamaño de un puntero en la mayoría de los sistemas). Con esto, necesitaría establecer el puntero a la dirección del espacio correctamente malloc.

Al declarar x sin 'estático', se convierte en una variable local y solo se inicializa una vez que se ejecuta la función propietaria. Y su espacio se toma de la pila, no del espacio global. (Esto todavía puede ser un problema para sistemas o hilos con una pila muy limitada.) El valor de YY ya se ha establecido en este punto, por lo que no hay problema.

también:

No recuerdo si hay alguna garantía de que las variables globales se inicializan en cualquier orden. Si no, entonces x podría inicializarse antes de YY. Si eso sucediera, YY solo contendría el contenido aleatorio de la RAM.

Cuestiones relacionadas