93 votes

Déclarations de variables dans les fichiers d'en-tête - statiques ou non ?

Lors de la refactorisation de certains #defines Je suis tombé sur des déclarations similaires à la suivante dans un fichier d'en-tête C++ :

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

La question est de savoir quelle différence, le cas échéant, fera la statique. Notez que l'inclusion multiple des en-têtes n'est pas possible en raison de la classique #ifndef HEADER #define HEADER #endif (si cela compte).

Est-ce que le statique signifie qu'une seule copie de VAL est créé, dans le cas où l'en-tête est inclus par plus d'un fichier source ?

0 votes

2voto

Jan de Vos Points 1615

Le livre C (gratuit en ligne) contient un chapitre sur la liaison, qui explique plus en détail la signification de "statique" (bien que la réponse correcte soit déjà donnée dans d'autres commentaires) : http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

2voto

itj Points 773

Pour répondre à la question "la statique signifie-t-elle qu'une seule copie de VAL est créée, dans le cas où l'en-tête est inclus par plus d'un fichier source ?"...

NON . VAL sera toujours défini séparément dans chaque fichier qui inclut l'en-tête.

Les normes pour C et C++ font une différence dans ce cas.

En C, les variables à l'échelle du fichier sont externes par défaut. Si vous utilisez le langage C, VAL est statique et ANOTHER_VAL est externe.

Notez que les linkers modernes peuvent se plaindre de ANOTHER_VAL si l'en-tête est inclus dans différents fichiers (même nom global défini deux fois), et se plaindraient certainement si ANOTHER_VAL était initialisé à une valeur différente dans un autre fichier.

En C++, les variables orientées fichier sont statiques par défaut si elles sont const, et externes par défaut si elles ne le sont pas. Si vous utilisez C++, VAL et ANOTHER_VAL sont toutes deux statiques.

Vous devez également tenir compte du fait que les deux variables sont désignées par const. Idéalement, le compilateur choisirait toujours de mettre ces variables en ligne et de ne pas inclure de stockage pour elles. Il existe toute une série de raisons pour lesquelles le stockage peut être alloué. Celles auxquelles je pense...

  • options de débogage
  • adresse prise dans le dossier
  • le compilateur alloue toujours du stockage (les types const complexes ne peuvent pas facilement être inlined, donc devient un cas spécial pour les types de base)

1voto

Seb Rose Points 2145

Si l'on suppose que ces déclarations ont une portée globale (c'est-à-dire qu'elles ne sont pas des variables membres), alors.. :

statique signifie "lien interne". Dans ce cas, puisqu'il est déclaré const ceci peut être optimisé/intégré par le compilateur. Si vous omettez l'élément const alors le compilateur doit allouer du stockage dans chaque unité de compilation.

En omettant statique le lien est externe par défaut. Encore une fois, vous avez été sauvé par le const ness - le compilateur peut optimiser l'utilisation/inline. Si vous laissez tomber le const alors vous obtiendrez un symboles définis de façon multiple erreur au moment de la liaison.

1voto

Gajendra Kumar Points 11

Vous ne pouvez pas déclarer une variable statique sans la définir également (ceci est dû au fait que les modificateurs de classe de stockage static et extern sont mutuellement exclusifs). Une variable statique peut être définie dans un fichier d'en-tête, mais cela aurait pour conséquence que chaque fichier source incluant le fichier d'en-tête aurait sa propre copie privée de la variable, ce qui n'est probablement pas ce qui était prévu.

1voto

bruzzo Points 92

const Les variables sont par défaut statiques en C++, mais extern C. Donc si vous utilisez C++ cela n'a pas de sens quelle construction utiliser.

(7.11.6 C++ 2003, et Apexndix C a des échantillons)

Exemple de comparaison des sources compilées/liées en tant que programme C et C++ :

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X