const static int foo = 42;
J'ai vu cela dans un code ici sur StackOverflow et je ne pouvais pas comprendre ce que cela faisait. Ensuite, j'ai vu des réponses confuses sur d'autres forums. Ma meilleure hypothèse est qu'il est utilisé en C pour masquer la constante foo
des autres modules. Est-ce correct? Si tel est le cas, pourquoi quelqu'un l'utiliserait-il dans un contexte C ++ où vous pouvez simplement le faire private
?
Beaucoup de gens ont donné la réponse de base mais personne n'a fait remarquer qu'en C ++, la valeur par
const
défaut étaitstatic
aunamespace
niveau (et certains ont donné des informations erronées). Consultez la section 3.5.3 de la norme C ++ 98.Tout d'abord un peu de contexte:
Unité de traduction: un fichier source après que le pré-processeur a inclus (récursivement) tous ses fichiers d'inclusion.
Liaison statique: un symbole n'est disponible que dans son unité de traduction.
Lien externe: un symbole est disponible auprès d'autres unités de traduction.
Au
namespace
niveauCela inclut l'espace de noms global aka les variables globales .
Au niveau de la fonction
static
signifie que la valeur est conservée entre les appels de fonction.La sémantique des
static
variables de fonction est similaire aux variables globales en ce qu'elles résident dans le segment de données du programme (et non dans la pile ou le tas), voir cette question pour plus de détails surstatic
la durée de vie des variables.Au
class
niveaustatic
signifie que la valeur est partagée entre toutes les instances de la classe etconst
signifie qu'elle ne change pas.la source
const int *foo(int x) {const int b=x;return &b};
par rapport àconst int *foo(int x) {static const int b=x;return &b};
const
seule implicationstatic
dans ce dernier.const
déclaration impliquestatic
là aussi? Comme dans, si vous rejetezconst
et modifiez la valeur, toutes les valeurs seront modifiées?const
n'implique pas de statique au niveau de la fonction, ce serait un cauchemar de concurrence (const! = Expression constante), tout au niveau de la fonction l'est implicitementauto
. Puisque cette question est également étiquetée [c], je dois mentionner qu'un niveau globalconst int
est implicitementextern
en C. Les règles que vous avez ici décrivent parfaitement le C ++, cependant.static
indique que la variable est de durée statique (une seule copie existe, qui dure du début du programme jusqu'à sa fin), et qu'elle a un lien interne / statique si ce n'est pas spécifié autrement (ceci est remplacé par la fonction lien pour les variables statiques locales, ou le lien de classe pour les membres statiques). Les principales différences sont dans ce que cela implique dans chaque situation oùstatic
est valable.Cette ligne de code peut en fait apparaître dans plusieurs contextes différents et bien qu'elle se comporte à peu près de la même manière, il existe de petites différences.
Étendue de l'espace de noms
'
i
' sera visible dans chaque unité de traduction qui comprend l'en-tête. Cependant, à moins que vous n'utilisiez réellement l'adresse de l'objet (par exemple. '&i
'), Je suis à peu près sûr que le compilateur traitera 'i
' simplement comme un type sûr0
. Là où deux autres unités de traduction prennent le «&i
», l'adresse sera différente pour chaque unité de traduction.'
i
' a un lien interne et ne peut donc pas être référencé de l'extérieur de cette unité de traduction. Cependant, à moins que vous n'utilisiez son adresse, elle sera très probablement traitée comme un type sécurisé0
.Il convient de souligner que la déclaration suivante:
est exactement le même que
static const int i = 0
. Une variable dans un espace de noms déclaré avecconst
et non explicitement déclarée avecextern
est implicitement statique. Si vous pensez à cela, il était l'intention du comité C ++ de permettre auxconst
variables d'être déclarées dans les fichiers d'en-tête sans toujours avoir besoin dustatic
mot - clé pour éviter de casser l'ODR.Portée de la classe
Dans l'exemple ci-dessus, la norme spécifie explicitement que «
i
» n'a pas besoin d'être défini si son adresse n'est pas requise. En d'autres termes, si vous n'utilisez «i
» que comme un 0 de type sécurisé, le compilateur ne le définira pas. Une différence entre les versions de classe et d'espace de noms est que l'adresse de «i
» (si elle est utilisée dans deux unités de traduction ou plus) sera la même pour le membre de la classe. Lorsque l'adresse est utilisée, vous devez en avoir une définition:la source
C'est une optimisation de petit espace.
Quand tu dis
Vous ne définissez pas une constante, mais créez une variable en lecture seule. Le compilateur est assez intelligent pour utiliser 42 chaque fois qu'il voit foo, mais il allouera également de l'espace dans la zone de données initialisée pour cela. Ceci est fait parce que, comme défini, foo a un lien externe. Une autre unité de compilation peut dire:
extern const int foo;
Pour accéder à sa valeur. Ce n'est pas une bonne pratique car cette unité de compilation n'a aucune idée de la valeur de foo. Il sait juste que c'est un const int et doit recharger la valeur de la mémoire chaque fois qu'il est utilisé.
Maintenant, en déclarant qu'il est statique:
Le compilateur peut faire son optimisation habituelle, mais il peut aussi dire "hé, personne en dehors de cette unité de compilation ne peut voir foo et je sais qu'il est toujours 42 donc il n'est pas nécessaire de lui allouer de l'espace".
Je dois également noter qu'en C ++, la meilleure façon d'empêcher les noms de s'échapper de l'unité de compilation actuelle est d'utiliser un espace de noms anonyme:
la source
Il manque un «int». Ça devrait être:
En C et C ++, il déclare une constante entière avec une portée de fichier local de valeur 42.
Pourquoi 42? Si vous ne savez pas déjà (et il est difficile de croire que vous ne le faites pas), c'est une référence à la réponse à la vie, à l'univers et à tout .
la source
En C ++,
est la meilleure façon de définir et d'utiliser des constantes. Ie utiliser ceci plutôt que
parce qu'il ne subvertit pas le système de sécurité de type.
la source
À toutes les bonnes réponses, je veux ajouter un petit détail:
Si vous écrivez des plugins (par exemple des DLL ou des bibliothèques .so à charger par un système de CAO), alors statique est un sauveur de vie qui évite les collisions de noms comme celle-ci:
Pire encore: l'étape 3 peut se comporter différemment selon l'optimisation du compilateur, le mécanisme de chargement du plugin, etc.
J'ai eu ce problème une fois avec deux fonctions d'assistance (même nom, comportement différent) dans deux plugins. Les déclarer statiques a résolu le problème.
la source
Selon la spécification C99 / GNU99:
static
est un spécificateur de classe de stockage
les objets de portée de niveau fichier ont par défaut une liaison externe
const
est un qualificatif de type (fait partie du type)
mot-clé appliqué à l'instance de gauche immédiate - ie
MyObj const * myVar;
- pointeur non qualifié vers le type d'objet qualifié constMyObj * const myVar;
- pointeur qualifié const vers un type d'objet non qualifiéUtilisation la plus à gauche - appliquée au type d'objet, pas variable
const MyObj * myVar;
- pointeur non qualifié vers le type d'objet qualifié constDONC:
static NSString * const myVar;
- pointeur constant vers une chaîne immuable avec liaison interne.L'absence du
static
mot - clé rendra le nom de la variable global et pourrait entraîner des conflits de nom au sein de l'application.la source
inline
Variables C ++ 17Si vous avez googlé "C ++ const static", alors c'est très probablement ce que vous voulez vraiment utiliser sont des variables en ligne C ++ 17 .
Cette fonctionnalité impressionnante de C ++ 17 nous permet de:
constexpr
: Comment déclarer constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Compilez et exécutez:
GitHub en amont .
Voir aussi: Comment fonctionnent les variables en ligne?
Norme C ++ sur les variables en ligne
La norme C ++ garantit que les adresses seront les mêmes. C ++ 17 N4659 standard draft 10.1.6 "Le spécificateur en ligne":
cppreference https://en.cppreference.com/w/cpp/language/inline explique que si ce
static
n'est pas donné, alors il a un lien externe.Implémentation de variables en ligne GCC
On peut observer comment il est implémenté avec:
qui contient:
et
man nm
dit à propos deu
:on voit donc qu'il existe une extension ELF dédiée à cela.
Pré-C ++ 17:
extern const
Avant C ++ 17, et en C, nous pouvons obtenir un effet très similaire avec un
extern const
, ce qui conduira à l'utilisation d'un seul emplacement mémoire.Les inconvénients
inline
sont:constexpr
avec cette technique,inline
permet seulement que: Comment déclarer constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub en amont .
Alternatives d'en-tête pré-C ++ 17 uniquement
Ce ne sont pas aussi bons que la
extern
solution, mais ils fonctionnent et n'occupent qu'un seul emplacement mémoire:Une
constexpr
fonction, carconstexpr
impliqueinline
etinline
permet (force) la définition d'apparaître sur chaque unité de traduction :et je parie que tout compilateur décent intégrera l'appel.
Vous pouvez également utiliser une variable statique
const
ouconstexpr
comme dans:mais vous ne pouvez pas faire des choses comme prendre son adresse, sinon il devient utilisé odr, voir aussi: Définition des membres de données statiques constexpr
C
En C, la situation est la même que C ++ avant C ++ 17, j'ai téléchargé un exemple à l' adresse : Que signifie «statique» en C?
La seule différence est qu'en C ++, cela
const
impliquestatic
pour les globaux, mais ce n'est pas le cas en C: C ++ sémantique de `static const` vs` const`Un moyen de l'intégrer entièrement?
TODO: existe-t-il un moyen d'intégrer complètement la variable, sans utiliser de mémoire du tout?
Tout comme ce que fait le préprocesseur.
Cela nécessiterait en quelque sorte:
En relation:
Testé dans Ubuntu 18.10, GCC 8.2.0.
la source
Oui, il masque une variable dans un module des autres modules. En C ++, je l'utilise lorsque je ne veux / n'ai pas besoin de modifier un fichier .h qui déclenchera une reconstruction inutile d'autres fichiers. Aussi, j'ai mis le statique en premier:
En outre, en fonction de son utilisation, le compilateur n'allouera même pas de stockage pour lui et simplement "en ligne" la valeur où il est utilisé. Sans le statique, le compilateur ne peut pas supposer qu'il n'est pas utilisé ailleurs et ne peut pas en ligne.
la source
C'est une constante globale visible / accessible uniquement dans le module de compilation (fichier .cpp). BTW utilisant statique à cette fin est obsolète. Mieux vaut utiliser un espace de noms anonyme et une énumération:
la source
enum
a dans ce contexte. Voulez-vous élaborer? Ils neenums
sont généralement utilisés que pour empêcher le compilateur d'allouer de l'espace pour la valeur (bien que les compilateurs modernes n'aient pas besoin de ceenum
hack pour cela) et pour empêcher la création de pointeurs vers la valeur.Le rendre privé signifierait toujours qu'il apparaît dans l'en-tête. J'ai tendance à utiliser la méthode «la plus faible» qui fonctionne. Voir cet article classique de Scott Meyers: http://www.ddj.com/cpp/184401197 (il s'agit de fonctions, mais peut également être appliqué ici).
la source