2010-06-11 18 views
142

Aparece un error en la línea 6 (inicializo my_foo a foo_init) del siguiente programa y no estoy seguro de entender por qué.Error "el elemento inicializador no es constante" al intentar inicializar la variable con const

typedef struct foo_t { 
    int a, b, c; 
} foo_t; 

const foo_t foo_init = { 1, 2, 3 }; 
foo_t my_foo = foo_init; 

int main() 
{ 
    return 0; 
} 

Tenga en cuenta que esta es una versión simplificada de un proyecto de varios archivos más grande en el que estoy trabajando. El objetivo era tener una sola constante en el archivo objeto, que varios archivos podrían usar para inicializar una estructura de estado. Dado que se trata de un objetivo incrustado con recursos limitados y la estructura no es tan pequeña, no quiero copias múltiples de la fuente. Yo prefiero no utilizar:

#define foo_init { 1, 2, 3 } 

También estoy tratando de escribir código portable, así que necesito una solución que sea válida C89 o C99.

¿Tiene esto que ver con los ORG en un archivo de objeto? ¿Las variables inicializadas entran en un ORG y se inicializan copiando el contenido de un segundo ORG?

Tal vez solo necesite cambiar mi táctica y tener una función de inicialización para hacer todas las copias al inicio. A menos que haya otras ideas por ahí?

Respuesta

199

En lenguaje C, los objetos con duración de almacenamiento estático deben inicializarse con expresiones constantes o con inicializadores agregados que contienen expresiones constantes.

Un objeto "grande" nunca es una expresión constante en C, incluso si el objeto se declara como const.

Por otra parte, en el lenguaje C, el término "constante" se refiere a constantes literales (como 1, 'a', 0xFF y así sucesivamente) y los miembros de enumeración. Los objetos calificados por Const (de cualquier tipo) son no constantes en terminología de lenguaje C. No se pueden usar en inicializadores de objetos con duración de almacenamiento estática, independientemente de su tipo.

Por ejemplo, este es NO una constante

const int N = 5; /* `N` is not a constant in C */ 

Lo anterior N sería una constante en C++, pero no es una constante en C. Por lo tanto, si se intenta hacer

static int j = N; /* ERROR */ 

obtendrá el mismo error: un intento de inicializar un objeto estático con un no constante.

Esta es la razón por la que en el lenguaje C utilizamos predominantemente #define para declarar constantes con nombre, y también recurrimos a #define para crear inicializadores agregados con nombre.

+1

+5 por la buena explicación, pero sorprendentemente este programa compila bien en ideone: http://ideone.com/lx4Xed. ¿Es un error del compilador o una extensión del compilador? Gracias – Destructor

+2

@meet: No sé qué combinación de opciones de compilación ideone utiliza bajo el capó, pero sus resultados a menudo son extraños más allá de la descripción. Traté de compilar este código en Coliru (http://coliru.stacked-crooked.com/a/daae3ce4035f5c8b) y obtuve el error esperado, independientemente de la configuración del dialecto del lenguaje C que use. No veo nada de eso listado en el sitio web de GCC como extensión de lenguaje C. En otras palabras, no tengo idea de cómo y por qué se compila en ideone. Incluso si se compila como una extensión de idioma, aún debería generar un mensaje de diagnóstico en C. – AnT

+7

'enum {N = 5};' es una forma poco apreciada de declarar constantes sin tener que recurrir a '# define'. –

67

Es una limitación del idioma. En la sección 6.7.8/4:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

En la sección 6.6, la especificación define qué debe considerarse una expresión constante. No, donde dice que una variable const debe considerarse una expresión constante. Es legal que un compilador extienda esto (6.6/10 - An implementation may accept other forms of constant expressions), pero eso limitaría la portabilidad.

Si puede cambiar my_foo por lo que no tiene almacenamiento estático, debería estar bien:

int main() 
{ 
    foo_t my_foo = foo_init; 
    return 0; 
} 
5

Sólo para ilustración de comparar y contrastar El código es de http://www.geeksforgeeks.org/g-fact-80/ /El código falla en gcc y pasa en g ++/

#include<stdio.h> 
    int initializer(void) 
    { 
      return 50; 
    } 

    int main() 
    { 
    int j; 
    for (j=0;j<10;j++) 
    { 
    static int i = initializer(); 
    /*The variable i is only initialized to one*/ 
    printf(" value of i = %d ", i); 
    i++; 
    } 
    return 0; 
    } 
2

Esto es un poco viejo, pero me encontré con un problema similar. Puede hacer esto si usa un puntero:

#include <stdio.h> 
typedef struct foo_t { 
    int a; int b; int c; 
} foo_t; 
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 }; 
// or a pointer 
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 }); 
int main (int argc, char **argv) { 
    const foo_t *const f1 = &s_FooInit; 
    const foo_t *const f2 = s_pFooInit; 
    printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c); 
    printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c); 
    return 0; 
} 
+2

No veo una variable con duración de almacenamiento estático que se inicialice aquí. –

Cuestiones relacionadas