Lors de la refactorisation de certaines, #defines
je suis tombé sur des déclarations similaires aux suivantes 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, la statique fera-t-elle? Notez que l'inclusion multiple des en-têtes n'est pas possible en raison de l' #ifndef HEADER
#define HEADER
#endif
astuce classique (si cela compte).
La valeur statique signifie-t-elle qu'une seule copie de VAL
est créée, au cas où l'en-tête serait inclus par plus d'un fichier source?
Réponses:
Les
static
moyens qu'il y aura une copieVAL
pour chaque fichier source , il est inclus. Mais elle a aussi des moyens que les inclusions multiples ne seront pas donner lieu à de multiples définitions deVAL
qui entrent en collision au moment de la liaison. En C, sans le,static
vous devez vous assurer qu'un seul fichier source est définiVAL
tandis que les autres fichiers source le déclarentextern
. Habituellement, on le ferait en le définissant (éventuellement avec un initialiseur) dans un fichier source et en plaçant laextern
déclaration dans un fichier d'en-tête.static
les variables au niveau global ne sont visibles que dans leur propre fichier source, qu'elles y soient parvenues via une inclusion ou qu'elles aient été dans le fichier principal.Note de l'éditeur: en C ++, les
const
objets sans mots-clésstatic
niextern
dans leur déclaration le sont implicitementstatic
.la source
Les balises
static
et desextern
variables de portée fichier déterminent si elles sont accessibles dans d'autres unités de traduction (c.-à-d. Autres.c
ou.cpp
fichiers).static
donne le lien interne variable, en le cachant des autres unités de traduction. Cependant, les variables avec un lien interne peuvent être définies dans plusieurs unités de traduction.extern
donne le lien externe variable, le rendant visible aux autres unités de traduction. Cela signifie généralement que la variable ne doit être définie que dans une seule unité de traduction.La valeur par défaut (lorsque vous ne spécifiez pas
static
ouextern
) est l'un de ces domaines dans lesquels C et C ++ diffèrent.En C, les variables de portée fichier sont
extern
(liaison externe) par défaut. Si vous utilisez C,VAL
eststatic
etANOTHER_VAL
estextern
.En C ++, les variables de portée fichier sont
static
(liaison interne) par défaut si elles le sontconst
, etextern
par défaut si elles ne le sont pas. Si vous utilisez C ++, les deuxVAL
etANOTHER_VAL
sontstatic
.À partir d'un brouillon de la spécification C :
À partir d'un brouillon de la spécification C ++ :
la source
Le statique signifiera que vous obtenez une copie par fichier, mais contrairement à d'autres, il est parfaitement légal de le faire. Vous pouvez facilement tester cela avec un petit exemple de code:
test.h:
test1.cpp:
test2.cpp:
L'exécution de ceci vous donne cette sortie:
la source
TEST
c'était le casconst
, si LTO serait capable de l'optimiser dans un seul emplacement de mémoire. Mais-O3 -flto
de GCC 8.1 ne l'a pas fait.const
les variables en C ++ ont un lien interne. Donc, l'utilisationstatic
n'a aucun effet.ah
one.cpp
deux.cpp
S'il s'agissait d'un programme C, vous obtiendrez une erreur de «définition multiple» pour
i
(en raison d'un lien externe).la source
static
a pour effet de signaler clairement l'intention et la conscience de ce que l'on est en train de coder, ce qui n'est jamais une mauvaise chose. Pour moi, c'est comme inclurevirtual
lors de la neutralisation: nous n'avons pas à le faire, mais les choses semblent beaucoup plus intuitives - et cohérentes avec d'autres déclarations - lorsque nous le faisons.La déclaration statique à ce niveau de code signifie que le variabel n'est visible que dans l'unité de compilation courante. Cela signifie que seul le code de ce module verra cette variable.
si vous avez un fichier d'en-tête qui déclare une variable static et que cet en-tête est inclus dans plusieurs fichiers C / CPP, alors cette variable sera "locale" pour ces modules. Il y aura N copies de cette variable pour les N endroits où l'en-tête est inclus. Ils ne sont pas du tout liés les uns aux autres. Tout code dans l'un de ces fichiers source ne fera référence qu'à la variable déclarée dans ce module.
Dans ce cas particulier, le mot-clé "statique" ne semble pas apporter de bénéfice. Il me manque peut-être quelque chose, mais cela ne semble pas avoir d'importance - je n'ai jamais rien vu de tel auparavant.
Quant à l'inlining, dans ce cas, la variable est probablement inline, mais c'est uniquement parce qu'elle est déclarée const. Le compilateur est peut- être plus susceptible d'insérer des variables statiques de module en ligne, mais cela dépend de la situation et du code en cours de compilation. Il n'y a aucune garantie que le compilateur intégrera la «statique».
la source
const
, lestatic
est implicite et donc facultatif. Le corollaire est qu'il n'y a pas de risque d'erreurs de définition multiples comme l'a affirmé Mike F.Le livre C (gratuit en ligne) contient un chapitre sur les liens, qui explique plus en détail la signification de `` statique '' (bien que la bonne réponse soit déjà donnée dans d'autres commentaires): http://publications.gbdirect.co.uk/c_book /chapter4/linkage.html
la source
Pour répondre à la question, "le statique signifie-t-il 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 comprend l'en-tête.
Les normes pour C et C ++ provoquent une différence dans ce cas.
Notez que les éditeurs de liens modernes peuvent se plaindre de ANOTHER_VAL si l'en-tête est inclus dans des fichiers différents (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
Vous devez également tenir compte du fait que les deux variables sont désignées const. Idéalement, le compilateur choisirait toujours d'inline ces variables et de ne pas inclure de stockage pour elles. Il existe une multitude de raisons pour lesquelles le stockage peut être alloué. Ceux auxquels je peux penser ...
la source
En supposant 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, cela peut être optimisé / intégré par le compilateur. Si vous omettez le const, 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é enregistré par la const ness - le compilateur peut optimiser / utilisation en ligne. Si vous supprimez le const, vous obtiendrez une erreur de symboles multiples définis au moment de la liaison.
la source
Vous ne pouvez pas déclarer une variable statique sans la définir également (c'est parce que les modificateurs de classe de stockage static et extern s'excluent mutuellement). Une variable statique peut être définie dans un fichier d'en-tête, mais cela ferait en sorte que chaque fichier source contenant le fichier d'en-tête ait sa propre copie privée de la variable, ce qui n'est probablement pas ce qui était prévu.
la source
Les variables const sont par défaut statiques en C ++, mais extern C. Donc, si vous utilisez C ++, la construction à utiliser n'a aucun sens.
(7.11.6 C ++ 2003 et Apexndix C a des exemples)
Exemple de comparaison des sources de compilation / liaison en tant que programme C et C ++:
la source
static
. Il signale l'intention / la conscience de ce que fait le programmeur et maintient la parité avec d'autres types de déclaration (et, fwiw, C) qui n'ont pas l'implicitestatic
. C'est comme inclurevirtual
et dernièrementoverride
dans les déclarations de fonctions primordiales - pas nécessaire, mais beaucoup plus auto-documenté et, dans le cas de ces dernières, propice à l'analyse statique.const
n'est utilisé que sur une variable dans un en-tête avecg++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
. Il en a résulté environ 150 symboles multi-définis (un pour chaque unité de traduction, l'en-tête était inclus). Je pense que nous avons besoin soitstatic
,inline
soit d'un espace de noms anonyme / sans nom pour éviter le lien externe.const int
dans la portée de l'espace de noms et dans l'espace de noms global. Et il est compilé et suit la règle "Les objets déclarés const et non explicitement déclarés extern ont un lien interne." ".... Peut-être dans le projet, pour une raison quelconque, cet en-tête inclus dans les sources compilées en C, où les règles complètement différentes.Static empêche une autre unité de compilation d'externaliser cette variable afin que le compilateur puisse simplement "insérer" la valeur de la variable là où elle est utilisée et ne pas créer de stockage mémoire pour elle.
Dans votre deuxième exemple, le compilateur ne peut pas supposer qu'un autre fichier source ne l'externera pas, il doit donc stocker cette valeur quelque part en mémoire.
la source
Static empêche le compilateur d'ajouter plusieurs instances. Cela devient moins important avec la protection #ifndef, mais en supposant que l'en-tête est inclus dans deux bibliothèques séparées et que l'application est liée, deux instances seraient incluses.
la source
static
«moins important». et même avec les deux, vous pouvez vous retrouver avec plusieurs définitions liées en interne, ce qui n'est probablement pas prévu.