2010-03-27 6 views
15

Existe-t-il une différence entre une variable déclarée static en dehors de toute fonction entre C et C++. J'ai lu que static signifie la portée du fichier et les variables ne seront pas accessibles en dehors du fichier. Je lis aussi que dans C, les variables globales sont static. Cela signifie-t-il que les variables globales dans C ne peuvent pas être accédées dans un autre fichier?Variables statiques en C et C++

Répondre

16

Non, il n'y a pas de différence entre C et C++ à cet égard.

Lire this SO answer à propos de ce que signifie static dans un programme C. En C++, il y a quelques autres significations liées à l'utilisation de static pour les variables de classe (au lieu de variables d'instance). En ce qui concerne les vars globaux étant static - seulement du point de vue de l'allocation de mémoire (ils sont alloués sur le segment de données, comme toutes les globales sont). Du point de vue de la visibilité.

static int var; // can't be seen from outside files 
int var;   // can be seen from outside files (no 'static') 
+0

'extern' ne fonctionnera pas avec' static' droit? peut être je suis trop confus .. – Naveen

+0

@Naveen: il n'y a pas de problème, * à moins que * vous l'avez déclaré 'static' –

+0

Ok..so dans le second cas, quelle sera la classe de stockage pour la variable' var'? Y a-t-il un nom ou est-ce simplement une variable globale? – Naveen

7

Il y a deux concepts ici « statique lien (ou étendue) » et l'allocation statique »

En dehors d'une fonction du mot-clé fait référence à la liaison, à l'intérieur se réfère à l'allocation. Toutes les variables en dehors d'une fonction ont allocation statique implicite. un design malheureux peut-être, mais il est.

5

C et C++ sont les mêmes.

statique fait deux choses différentes.

Pour les variables déclarées en dehors d'une portée de fonction, elle modifie la visibilité (liaison) de la variable. La variable sera une variable globale puisqu'elle est en dehors d'une portée de fonction. S'il n'est pas statique, il aura un lien universel (visibilité) donc tout code lié avec celui-ci peut y accéder (il peut être nécessaire de le déclarer extern). Si la variable est en dehors d'une portée de fonction et est statique, elle reste une variable globale en ce qu'elle existe toujours et conserve sa valeur, mais aucun code en dehors de la même unité de compilation (fichier .c et n'importe quel .h inclus) n'y accède.

Pour les variables déclarées à l'intérieur d'une portée de fonction, statique modifie l'emplacement où la variable est stockée. S'il n'est pas statique, il s'agira d'une variable automatique, c'est-à-dire qu'elle disparaîtra à mesure que la fonction sort et revient à l'existence (sur la pile) lorsque la fonction est à nouveau saisie. Cela perd sa valeur lorsque vous quittez la fonction. Et toutes les références à celui-ci (pointeurs vers lui) sont invalides après la sortie de la fonction. Si une variable déclarée à l'intérieur d'une portée de fonction est statique, alors elle n'en fait pas une variable automatique mais une variable globalement allouée. Ainsi, la variable existera après la sortie de la fonction et conservera ainsi sa valeur à travers les invocations de la fonction et aussi toutes les références (pointeurs) à celle-ci sont valides même après la sortie de la fonction. Notez que dans les deux cas, la portée de la variable est seulement dans cette fonction, il n'est donc pas possible d'y accéder directement (mais seulement via une référence sauvegardée) depuis l'extérieur de la portée de la fonction.

Une dernière chose statique est le changement lorsque l'initialiseur (c'est-à-dire int foo = 5) pour la variable est exécuté. Pour tous les cas où l'allocation est globale (tous les cas sauf l'automatique), l'initialiseur n'est exécuté qu'une seule fois, au début de l'exécution de votre programme. Il est exécuté avant que main() ne soit exécuté de manière régulière, de sorte que vous pouvez obtenir un résultat pas tout à fait attendu si votre initialiseur n'est pas simplement un nombre constant mais exécute du code. Pour le cas automatique, l'initialiseur est exécuté à chaque fois que la fonction est entrée, et dans ce cas toujours après l'entrée de main().

+0

Etes-vous sûr que les variables statiques dans une fonction sont initialisées avant main()? J'ai toujours pensé qu'ils ont été initialisés la première fois que la fonction a été appelée, et c'est aussi ce que les réponses disent ici: http://stackoverflow.com/questions/246564/what-is-the-lifetime-of-a-static-variable -in-ac-function –

+0

Les réponses dans ce thread sont pour C++. Je suppose que mon hypothèse que C et C++ le font pareil est incorrect.Certaines recherches indiquent que C n'autorise que les initialiseurs constants et qu'ils sont remplis au moment de la compilation et non à l'exécution. Donc c'est avant main() à mon crédit. Mais je me suis trompé sur le reste, C++ le fait différemment et donc tous les cas qui importent doivent être interprétés en fonction du lien que vous avez inséré. –

1

Je veux ajouter à la réponse de Southern Hospitality Static variables in C and C++

les remarques suivantes:

L'utilisation de static pour indiquer "unité locale de traduction" est dépréciée en C++ (href = "http: // rads.stackoverflow.com/amzn/click/0201700735 "Langage de programmation C++: édition spéciale, Annexe B.2.3, Fonctionnalités obsolètes".

Vous devez utiliser les espaces de noms sans nom au lieu:

static int reply = 42; // deprecated 

namespace { 
    int reply1 = 42; // The C++ way 
} 

Comme déjà dit par Southern Hospitality, l'ordre d'initialisation des objets globaux est indéfini. Dans cette situation, vous devriez envisager d'utiliser href = "http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B", motif Singleton.

MISE À JOUR: GMan a commenté ma réponse:

« L'ordre est défini par unité-traduction, ... »: Cela a vraiment glissé mon esprit, donc je l'ai regardé dans le langage C++ de programmation.

Dans la section 9.4.1, Initialisation des variables non locales, le professeur Stroustrup suggère que « une fonction renvoyant une référence est une bonne alternative à une variable globale »:

int& use_count() 
{ 
     static int uc = 0; 
     return uc; 
} 

« Un appel à use_count() maintenant agit comme une variable globale qui est initialisé à sa première utilisation. Par exemple: »

void f() 
{ 
     std::cout << ++use_count() << '\n'; 
} 

Dans ma compréhension, ce qui est très semblable au modèle Singleton. GMan a ajouté: «Nous devons limiter notre capacité à créer ces objets à un seul, et fournir un accès global à celui-ci. Est-ce que la limitation à un se rapporte vraiment à quelque chose dans le problème? Nous devrons peut-être un dans le monde, mais qui est-à-dire que nous ne voulons pas dans d'autres endroits «

Quelques citations de Singleton (127) (Gamma et al, Design Patterns):

»? Le modèle Singleton est une amélioration par rapport aux variables globales. Il évite la pollution de l'espace de noms avec des variables globales qui stockent des cas uniques. »

« Le modèle permet de changer facilement votre esprit et laisser plus d'une instance de la classe Singleton. »

singletons sont initialisés dans la . pour leur première utilisation

Dans Herb Sutter, Andrei Alexandrescu, C++ normes de codage, article 10 dit:

"Évitez les données partagées, en particulier les données globales."

donc j'utilise souvent Singletons pour éviter les données globales. Mais bien sûr, comme tout est surutilisable, cela pourrait être une surutilisation du modèle Singleton. (Johshua Kerievsky appelle cela "Singletonitis" dans son livre "refactorisation Patterns".)

MISE À JOUR 2:

(Désolé, mais je ne peux pas écrire des commentaires, donc cette mise à jour.Jalf a écrit dans son commentaire: "Le groupe de quatre fumait quelque chose d'illégal quand ils ont écrit sur le modèle singleton."

De toute évidence, d'autres développeurs C++ fumaient aussi des substances intéressantes. Par exemple, Herb Sutter (il a servi pendant plus d'une décennie en tant que secrétaire et président du comité de normalisation ISO C++ lors du développement de la deuxième norme C++, C++ 0x, et en tant qu'architecte principal de C++/CLI chez Microsoft. le concepteur du modèle de mémoire Prism pour les plates-formes Microsoft et les extensions Concur à Visual C++ pour la programmation parallèle), écrit dans C++ Coding Standards, article 21:

"Lorsque vous avez besoin d'une telle variable (niveau d'espace de noms) qui peut dépendre de un autre, considérer le modèle de conception de Singleton, utilisé avec précaution, pourrait éviter les dépendances implicites en s'assurant qu'un objet est initialisé lors du premier accès.Mais Singleton est une variable globale dans l'habillement du mouton, et est brisée par des dépendances mutuelles ou cycliques. Donc, évitez les données globales, si vous le pouvez. Mais si vous devez utiliser des données globales dans des unités de traduction séparées, Singleton devrait être une solution acceptable pour appliquer une séquence d'initialisation spécifique.

Notez que dans le langage Java, les données globales n'existent même pas. Évidemment, les données globales sont substituées/émulées par l'utilisation du modèle de conception de Singleton.

(Car je travaille dans mon dayjob avec une équipe Java, je cherche une similitude maximale de mes programmes C++ avec les programmes Java. Par exemple, chaque classe est situé dans son propre fichier source/unité de traduction.)

+0

La commande est définie par unité de traduction, pour ce qu'elle vaut. Mais j'espère que vous voyez que le modèle singleton n'est pas la solution. "L'ordre d'initialisation entre les unités n'est pas spécifié" -> "Nous devons limiter notre capacité à créer ces objets à un seul et fournir un accès global à celui-ci." Est-ce que la limitation à un se rapporte vraiment à quelque chose dans le problème? Nous en avons peut-être besoin d'un * globalement *, mais qui peut dire que nous ne le voulons pas ailleurs? – GManNickG

+2

@edit: Les singletons sont des données globales, peu importe comment vous les habillez. Peut également supprimer les restrictions inutiles et créer un wrapper global. http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/ – GManNickG

+1

Comment votre citation de Gamma et al a-t-elle même un sens? Les instances globales ne polluent plus un espace de noms que les singletons. (Prenez 'std :: cout' par exemple Une instance globale, visible dans l'espace de nom std Comment est votre fonction' f' mieux visible Que dans l'espace de nommage dans lequel elle est déclarée. Quant à la deuxième partie, non, Les singletons font qu'il est beaucoup plus difficile de changer d'avis.Toute votre base de code est encombrée d'appels à getInstance() ou d'accès implicites à des données statiques.J'en reste à ma conclusion: les quatre personnes fumaient quelque chose d'illégal quand elles ont écrit sur motif singleton. – jalf

0

Pas vraiment une réponse directe à votre question, mais quelque chose de étroitement lié à faire attention si vous utilisez à la fois C et C++. En C++, contrairement à C, les variables globales déclarées "const" sont implicitement locales à l'unité de traduction, AS IF "static" a été utilisé.

Exemple:

// file A 
extern const int glob; 

// file B 
const int glob = 42; 

Cela fonctionnera si vous utilisez un compilateur C, mais pas avec un compilateur C++. En C++, la variable glob du fichier B ne peut pas être utilisée à partir du fichier A et l'éditeur de liens générera une erreur de "référence non résolue". Comment puis-je accéder à une variable en dehors du fichier dans C?