7
votes

Y compris le fichier d'en-tête C avec beaucoup de variables globales

J'ai un fichier incluant avec plus de 100 variables globales. Il est utilisé dans une bibliothèque, mais certains programmes que je relie la lib afin d'accéder également aux globaux.

La façon dont il a été construit: xxx

i J'ai eu du mal à comprendre pourquoi le programmeur d'origine a fait que j'ai donc supprimé cela définissant des choses externes. Maintenant, je pense que je comprends la chose à propos de TU à l'aide de Stackoverflow: 1 , 2 , 3 .

Maintenant, je comprends que je devrais définir les variables globales dans un fichier .C dans la bibliothèque et utiliser externe dans le fichier .h. Le problème est que je ne veux pas dupliquer du code.

Dois-je revenir à ce #define extern Voodoo?

c gcc

1 commentaires

Désolé de monter ces derniers temps, mais la réponse acceptée est la mauvaise approche. La réponse de Frederik Slijkerman est la bonne. Seules les déclarations dans les fichiers .h et les définitions dans les fichiers .c. extern var est une déclaration, sans extern c'est une définition. Placez la définition de la variable dans le module (c'est-à-dire un fichier .c) il est logiquement (sémantiquement) une partie de. Inversement, jamais Utilisez un extern var dans un fichier .c.


8 Réponses :


6
votes

C'est un mauvais modèle de définir externe dans chaque fichier .c. Supprimer c'est probablement le meilleur, mais vous devez remplacer cette fonctionnalité en quelque sorte. Une approche est que vous pouvez utiliser un #define dans le fichier .C qui doit définir ces globaux. Cela définisse signalera à la .h à ne pas externe les variables globales.

Par exemple: La bibliothèque .c fichier .C: xxx

les autres fichiers .c: xxx

foo_library.h: xxx

ou xxx

Ceci réduit la nécessité de définir la même chose dans chaque fichier source (sauf un) et aiderait à réduire les erreurs. Je ne l'appellerai pas non plus externe comme cela peut simplement causer de la confusion, car il peut ou non être "externe"


2 commentaires

Je suis en désaccord que c'est un mauvais modèle: je sais que cela va à l'encontre de la sagesse perçue d'avoir les externes dans .h des fichiers, mais pour ce cas même, je ne peux penser à aucun autre inconvénient que d'avoir à écrire quelques définitions externes supplémentaires. Si vous trouvez la nécessité d'écrire des tonnes d'entre eux, votre code est un désordre (trop de variables globales) et vous devriez toujours penser à la manière dont vous les utilisez et où vous les utilisez, car ils peuvent causer des bugs très subtils. En utilisant un fichier .h, vous vous donnez une carte blanche pour utiliser des variables globales indiscriminantes.


Makis, vous vous confondez 2 choses ici; - le choix de conception d'utiliser des variables globales et des meilleures pratiques lorsque vous devez utiliser une variable globale. Il est clair que l'utilisation de variables globales est généralement une mauvaise idée, mais lorsque vous devez en utiliser un, utilisez la meilleure utilisation de son implémentation et c'est extern var Déclaration dans l'en-tête et var Définition dans la droite .c fichier. Tout autre modèle d'utilisation est faux.



2
votes

Je serais peut-être manquant quelque chose, mais je ne vois aucune différence entre le #define trucsy et simplement à l'aide du mot-clé

Fondamentalement, vous devez déclarer les VARS dans un fichier .h et les définir dans un fichier .C. Ne considérez pas la duplication de code informatique - je pense que changer le point de vue est la meilleure chose à faire ici :). Vous pouvez écrire plus de lignes de code, mais elles seront lisibles: ré.


4 commentaires

Je suis prêt à être que l'extérieur est placé dans la déclaration et les fichiers d'en-tête pour faire couper et coller la valeur JSUT qui plus facile à utiliser et d'avoir un Quant Visual qui a déclaré que la portée mondiale est visible. Cela dit, je frémise le merveilleux abus qui permet partout. Oh, les jours de Spaghetti Var Tracking ...


Eh bien, je fais cela pour dll_export et tel, mais c'est parce que M $ VC et GCC font différemment. En ce qui concerne les externes, je préfère vraiment simplement avoir un .h et un fichier .c pour eux. Comme je l'ai dit, c'est plus de code, mais j'aime la lisibilité. Peut-être que c'est juste une préférence personnelle, je ne sais pas. Encore une fois, étiez-moi pour ériter un code illisible, j'apprendais à programmer dans Brainfef * ck ou quelque chose de similaire :)


Cette chose même est la raison pour laquelle je spécifie des noms de variables mondiaux, même si je déteste la notation hongroise avec une vengeance. Selon le style du programme, j'utilise le préfixe "g" ou "g_" pour ceux-ci. Cela aide les inspections plus que vous ne pouviez croire.


+1 I Deuxièmement que je vais encore plus loin. Ne définissez jamais une variable globale dans un en-tête, jamais, pas d'exception, il n'appartient que la douleur et le chagrin. Inclure les fichiers doit être idempotent.



5
votes

Peut-être que je manque quelque chose aussi, mais je Toujours strong> Utilisez des gardes d'inclusion sur tous les fichiers d'en-tête I Créer:

FOO.H: P>

#include "foo.h"
#include <stdio.h>
int main(int argc, char** argv)
{
    printf("foo:%d\n",foo);
    return 0;
}


9 commentaires

Je pense que cette stratégie simple ne fonctionnera pas avec les bibliothèques et les programmes qui incluent le même fichier d'en-tête.


Je préfère beaucoup cela sur la méthode d'Aaron également énumérés ici. Avoir les définitions d'un dossier et que les déclarations d'une autre ont plus de sens pour moi et ressemblent à un modèle beaucoup plus commun.


Les gens, cela ne fonctionnera pas. Imaginez si je compile la bibliothèque et, à une date ultérieure, compilez un programme comprenant que .h fichier. Les deux auront les globaux sans externe. C'est la situation que je décris.


@Costi, Foo.c fait partie de la bibliothèque, les globaux sont dans la bibliothèque. Vos programmes incluront tous FOO.H - où les globaux sont définis externes. Les gardes d'inclusion permettront à chaque programme de construction séparément pour inclure FOO.H une fois. Pouvez-vous expliquer comment cela est cassé parce que je ne le vois pas.


Mes mauvais, les gars. Je vois maintenant que foo.c a "int foo = 0". Mais je vois toujours un problème avec cette approche: j'ai plus de 100 globaux et c'est beaucoup de dupliqué de code dans les fichiers .c et .h lib. Avec la solution d'Aaron, ils ne seront déclarés que dans le fichier .h.


@Costi: vrai je suppose. De quelques recherches rapides de "Cibliothèque C avec des variables globales", j'ai l'impression que les globaux dans une bibliothèque sont une mauvaise idée de toute façon. Si je le lisons correctement, si deux programmes d'exécution simultanément partagent le même ensemble de globaux ou avoir leurs propres copies, ne peuvent pas être invoqués et sont spécifiques au système d'exploitation, etc.


Je ne pense pas que les données soient partagées entre les processus d'exécution à l'aide de la même bibliothèque. Et, de toute façon, nous relions de manière statique à notre propre lib :)


@Costi: Si ce n'est pas votre bibliothèque, cela n'a pas de problème si les codes sont dupliqués. S'il s'agit de votre bibliothèque, vous devriez vraiment éviter d'utiliser ces nombreuses variables globales. Même la solution de Paul R est bien meilleure. James Morris donne la solution la plus standard.


+1. Vous ne devriez pas utiliser l'inclusion des fichiers d'en-tête pour inclure le "code" (par rapport aux définitions). Je sais que la ligne est floue ici, mais l'idée de quitter le mot clé externe offert efficacement la fonction d'en-tête, car la définition fonctionne, mais n'est qu'un sous-produit de la gestion des globaux «trop nombreux» (je sais que cela est subjectif, mais je 'm expliquer pourquoi ce modèle n'est pas aussi courant dans la nature.)



10
votes

Le truc ici est que le fichier .h est utilisé de deux manières différentes - il est utilisé comme un fichier normal .h si tous les globaux sont déclarés extern et il est également utilisé pour < em> définir les globaux eux-mêmes (sans extern ). C'est un hack moche mais vous pouvez comprendre pourquoi quelqu'un a estimé qu'il était nécessaire si vous avez un grand nombre de globaux (un signe sûr d'une très mauvaise conception de logiciels!).

Quoi qu'il en soit, il y a une solution quelque peu plus élégante - vous pouvez mettre Tous vos globaux dans une seule structure globale, par exemple xxx

- xxx

-

alors puis quand vous devez faire référence à un global, c'est par exemple globals.a au lieu de A , ce qui pourrait sembler un inconvénient, mais cela est sans doute plus clair et plus gérable que de simplement avoir des globaux nus dispersés dans le code.


1 commentaires

Vous avez raison et mettre ces globaux dans certaines structures est un todo. Il est même possible de leur donner des noms significatifs.



-1
votes

Bien que cela puisse être ennuyeux d'abord, il vous aide à éviter de taper la chose deux fois ou d'oublier d'inclure quelque chose dans un fichier .C du tout. J'ai vu: xxx

avec foo.h étant: xxx


1 commentaires

L'utilisation de déclarations globales sur la fonction est inutile. Le semi-points après le deuxième #define déclarer est erroné.



0
votes

En règle générale, n'utilisez pas de variables globales. Parfois, vous devez utiliser des variables statiques dans le fichier, mais il est préférable d'essayer de les éviter du tout:

  • Vous ne pouvez pas utiliser correctement le code de test qui contient des variables globales
  • Il n'y a pas de séparation propre entre les modules pouvant causer des problèmes d'isolement d'erreurs
  • Il est généralement pas fil sûr. Vous devez les envelopper avec des mautexes, etc. Si vous souhaitez utiliser des threads (tendance à être une meilleure et meilleure idée car nous obtenons de plus en plus de noyaux) Vous pouvez rencontrer des problèmes avec un état partagé écrit.

    Parfois, dans C, vous ne pouvez pas les éviter (surtout dans le code hérité par quelqu'un) mais le mieux est de les garder dehors.

    Quant à la déclaration - Cela pourrait être utile dans ce cas: xxx


0 commentaires

5
votes

Les choses macro sont stupides pour cela. Il suffit de mettre xxx pré>

dans votre fichier d'en-tête, et dans un fichier .C .c (typiquement un avec le même nom que le fichier .h), mettez p>

int myGlobal;


1 commentaires

Cela devrait être la réponse acceptée. C'est la seule approche sain d'esprit. Tout autre prepprocesseur Acrobatic présenté dans les autres réponses est incorrect, ajoutant un bruit inutile dans le code.



1
votes

Dans les grands programmes, il est très important de disposer d'une seule ligne de déclarer et de définir une variable globale. Par conséquent, l'approche macro décrite ci-dessus est la bonne façon de résoudre le problème.

// globals.h 
#ifndef GLOBALS_H 
#define GLOBALS_H  
#ifndef EXTERN 
#define EXTERN extern 
#endif
EXTERN int i; 
#endif  

// globals.c 
#define EXTERN 
#include "globals.h" 


0 commentaires