Initialiser une structure globale en C
Quelle est la meilleure façon d'accomplir ce qui suit en Do?
#include <stdio.h>
struct A
{
int x;
};
struct A createA(int x)
{
struct A a;
a.x = x;
return a;
}
struct A a = createA(42);
int main(int argc, char** argv)
{
printf("%dn", a.x);
return 0;
}
Lorsque j'essaie de compiler le code ci-dessus, le compilateur signale l'erreur suivante:
"initialiseur élément n'est pas constante"
La mauvaise ligne est celui-ci:
struct A a = createA(42);
Quelqu'un peut-il expliquer ce qui ne va pas? Je ne suis pas très expérimenté en C. Merci!
6 réponses
Pourquoi ne pas utiliser initialisation statique?
struct A a = { 42 };
struct A a = { .x = 42 };
Plus de membres:
struct Y {
int r;
int s;
int t;
};
struct Y y = { .r = 1, .s = 2, .t = 3 };
Vous pouvez aussi faire
struct Y y = { 1, 2, 3 };
La même chose travaille pour les syndicats, et vous n'avez pas à inclure tous les membres ou même les mettre dans le bon ordre.
le problème ici est que les variables statiques global / file en C doivent avoir une valeur connue au moment de la compilation. Cela signifie que vous ne pouvez pas utiliser une fonction définie par l'utilisateur pour initialiser la valeur. Il doit être une expression constante
Vous ne pouvez pas invoquer fonctions initialisation statique comme ça. Dans votre exemple, vous pouvez simplement utiliser:
struct A a = {42};
si vous avez une configuration plus compliquée, vous devrez fournir une fonction de construction de bibliothèque et de destruction de bibliothèque que vous forcerez les utilisateurs de votre bibliothèque à appeler( en supposant que vous voulez être portable), ou vous devrez utiliser C++ et profiter de constructeurs/destructeurs, ou vous devrez profiter de la non standard et non portable __attribute__((constructeur)) pour créer une fonction qui est exécutée au démarrage de l'initialiser.
Si vous avez plus compliqué de l'installation, je vous recommande fortement que vous utilisez C++:
class A { A(){ // can do initialization in the constructor } // ... }; A a;
cependant, si vous avez besoin de coller avec du C pur, la chose portable à faire est d'utiliser quelque chose comme:
typedef void* mylibrary_attr_t; typedef void* mylibrary_t; #ifdef __cplusplus # define EXTERNC extern "C" #else # define EXTERNC #endif EXTERNC int mylibrary_attr_init(mylibrary_attr_t*); EXTERNC int mylibrary_attr_setparam1(mylibrary_attr_t,int); EXTERNC int mylibrary_attr_setparam2(mylibrary_attr_t,double); // .. more functions for various attributes used by library EXTERNC void mylibrary_attr_destroy(mylibrary_attr_t*); EXTERNC int mylibrary_init(mylibrary_t*,mylibrary_attr_t); EXTERNC void mylibrary_destroy(mylibrary_t*); // functions that use mylibrary_t // ...
en gros, dans ce qui précède, vous initialiseriez votre bibliothèque avec mylibrary_init
et démonter votre bibliothèque en utilisant mylibrary_destroy
. Les fonctions utilisant votre bibliothèque nécessiteraient instance initialisée de mylibrary_t
, et donc la personne qui a créé la fonction principale serait chargé d'invoquer mylibrary_init
. Il est également bon de rendre la fonction d'initialisation dépendante d'un paramètre "attributs" qui peut être remplacé par 0 ou NULL par défaut. De cette façon, si vous étendez votre bibliothèque et que vous devez accepter les options de configuration, elle est disponible pour vous. C'est plus un design qu'une approche technique.
Pour les curieux qui l'utilisent également MSVC:
en C, il est possible d'exécuter des fonctions d'initialisation avant main tout comme il est possible en C++ (bien sûr, comment C++ le ferait si ce n'était pas possible en C), mais il peut être quelque peu confus si vous n'avez pas lu comment fonctionne votre bibliothèque runtime.
pour faire court:
#pragma section(".CRT$XIU",long,read)
int
init_func ()
{
// initialization
return 0; // return 0 is mandatory
}
__declspec(allocate(".CRT$XIU"))
int (*global_initializer)() = init_func;
donc ce n'est pas un texte source aussi compact qu'en C++, mais ça peut être fait. Aussi, avant d'utiliser je recommande de comprendre PE formater d'abord, puis lire crt\src\crt0.c et crt\src\crt0dat.c (rechercher _cinit dans les deux fichiers) dans votre répertoire D'installation MSVC pour que vous sachiez ce qui se passe.
Vous ne pouvez pas appeler une fonction comme initiliazer. Vous avez besoin de l'appeler, à l'intérieur.