2010-06-11 3 views
142

Je reçois une erreur sur la ligne 6 (initialiser my_foo à foo_init) du programme suivant et je ne suis pas sûr de comprendre pourquoi. Gardez à l'esprit qu'il s'agit d'une version simplifiée d'un projet multi-fichiers plus important sur lequel je travaille actuellement. Le but était d'avoir une seule constante dans le fichier objet, que plusieurs fichiers pourraient utiliser pour initialiser une structure d'état. Comme il s'agit d'une cible intégrée avec des ressources limitées et que la structure n'est pas si petite, je ne veux pas de multiples copies de la source. Je préfère ne pas utiliser:Erreur "l'élément d'initialisation n'est pas constant" lors de l'initialisation de la variable avec const

#define foo_init { 1, 2, 3 } 

Je suis aussi en train d'écrire du code portable, donc je besoin d'une solution qui est valide C89 ou C99.

Cela concerne-t-il les ORG dans un fichier objet? Les variables initialisées vont dans un ORG et sont initialisées en copiant le contenu d'un second ORG?

Peut-être que je vais juste besoin de changer de tactique, et avoir une fonction d'initialisation faire toutes les copies au démarrage. À moins qu'il y ait d'autres idées?

Répondre

199

En langage C les objets avec une durée de stockage statique doivent être initialisés avec des expressions constantes ou avec des initialiseurs agrégés contenant des expressions constantes.

Un "grand" objet n'est jamais une expression constante dans C, même si l'objet est déclaré const.

De plus, en langage C, le terme "constante" fait référence à constantes littérales (comme 1, 'a', 0xFF et ainsi de suite) et les membres de ENUM. Les objets qualifiés Const (de tout type) sont et non les constantes dans la terminologie du langage C. Ils ne peuvent pas être utilisés dans les initialiseurs d'objets avec une durée de stockage statique, quel que soit leur type.

Par exemple, cela est pas une constante

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

ci-dessus N serait une constante en C++, mais il est pas une constante en C. Donc, si vous essayez de faire

static int j = N; /* ERROR */ 

vous obtiendrez la même erreur: une tentative d'initialisation d'un objet statique avec un non-constant.

C'est la raison pour laquelle en langage C, nous utilisons principalement #define pour déclarer des constantes nommées, et aussi #define pour créer des initialiseurs agrégés nommés.

+1

+5 pour la bonne explication, mais étonnamment ce programme se compile bien sur ideone: http://ideone.com/lx4Xed. Est-ce un bug du compilateur ou une extension du compilateur? Merci – Destructor

+2

@meet: Je ne sais pas quelle combinaison d'options de compilateur ideone utilise sous le capot, mais leurs résultats sont souvent étranges au-delà de la description. J'ai essayé de compiler ce code sur Coliru (http://coliru.stacked-crooked.com/a/daae3ce4035f5c8b) et j'ai obtenu l'erreur attendue, quel que soit le paramétrage du dialecte en langage C que j'ai utilisé. Je ne vois rien de semblable à cela sur le site Web de GCC en tant qu'extension de langage C. En d'autres termes, je n'ai aucune idée de comment et pourquoi il compile dans ideone. Même s'il se compile comme une extension de langage, il devrait quand même produire un message de diagnostic dans C. – AnT

+7

'enum {N = 5};' est une façon sous-estimée de déclarer des constantes sans devoir recourir à '# define'. –

67

C'est une limitation de la langue. Dans la section 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.

Dans la section 6.6, la spécification définit ce qui doit être considéré comme une expression constante. Non, où indique-t-on qu'une variable const doit être considérée comme une expression constante. Il est légal pour un compilateur d'étendre ceci (6.6/10 - An implementation may accept other forms of constant expressions) mais cela limiterait la portabilité.

Si vous pouvez changer my_foo il ne dispose pas de stockage statique, vous seriez d'accord:

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

Juste pour illustration de comparer et contraster Le code est de http://www.geeksforgeeks.org/g-fact-80/ /Le code échoue dans gcc et passe 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

C'est un peu vieux, mais je suis tombé sur un problème similaire. Vous pouvez le faire si vous utilisez un pointeur:

#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

Je ne vois pas une variable avec une durée de stockage statique qui est initialisée par un non-constant ici. –