2009-06-25 10 views
7

Je suis nouveau à C. J'ai un livre devant moi qui explique la «portée du fichier» de C, y compris un exemple de code. Mais le code ne déclare et n'initialise qu'une variable de portée de fichier - il ne vérifie pas la portée de la variable en essayant, par exemple, d'y accéder de manière illégale. Alors! Dans l'esprit de la science, j'ai construit une expérience.En C, comment puis-je limiter la portée d'une variable globale au fichier dans lequel elle est déclarée?

fichier bar.c:

static char fileScopedVariable[] = "asdf"; 

fichier foo.c:

#include <stdio.h> 
#include "bar.c" 

main() 
    { 
    printf("%s\n", fileScopedVariable); 
    } 

Selon mon livre, et Google, l'appel à printf() devrait échouer - mais il ne fonctionne pas. foo.exe sort la chaîne "asdf" et se termine normalement. J'aimerais beaucoup utiliser la portée du fichier. Qu'est-ce que je rate?

+4

L'appel d'une variable définie avec un 'champ d'application' statique est un terme inapproprié. Il est limité à une seule unité de traduction, résultat du collage récursif de tous les fichiers #include. – Eric

Répondre

15

Vous avez # inclus bar.c, ce qui a pour effet de faire littéralement copier le contenu de bar.c dans foo.c par le préprocesseur avant que le compilateur ne le touche. Essayez de vous débarrasser de l'inclusion, mais demandez à votre compilateur de compiler les deux fichiers (par exemple gcc foo.c bar.c) et regardez-le se plaindre comme vous l'attendez.

Éditer: Je suppose que la confusion primaire est entre le compilateur et le préprocesseur. Les règles de langage sont appliquées par le compilateur. Le préprocesseur s'exécute avant le compilateur et agit sur les commandes préfixées par #. Tout le préprocesseur ne manipule que du texte brut. Il n'analyse pas le code ou n'essaie pas d'interpréter la signification du code de quelque façon que ce soit. La directive "#include" est très littérale - elle indique au préprocesseur "insérer le contenu de ce fichier ici". C'est pourquoi vous n'utilisez normalement que #include sur les fichiers .h (en-tête), et vous ne placez que des prototypes de fonctions et des déclarations de variables externes dans les fichiers d'en-tête. Sinon, vous finirez par compiler les mêmes fonctions, ou définir les mêmes variables, plusieurs fois, ce qui n'est pas légal.

+0

Merci, monsieur! Je l'ai fait fonctionner. – Metaphile

0

Supprimez la deuxième instruction include. Comme il a été dit ci-dessus ...

Avant de compiler votre code, un compilateur le prétraite. À ce stade, il traite toutes les instructions commençant par '#', comme #include, #define et etc.

Pour voir le résultat de cette étape, vous pouvez simplement lancer 'gcc -E' (si vous utilisez gcc) .

6

Ceci est causé par des termes prêtant à confusion. file scope en C ne se réfère pas à restreindre le couplage d'un identifiant à une seule unité de traduction. Cela ne signifie pas non plus que la portée est limitée à un fichier physique. Au lieu de cela, file scope signifie que votre identifiant est global. Le terme file, ici, se réfère au texte qui résulte du traitement de tous les #include, #define et d'autres directives de pré-processeur.

En général, la portée n'est qu'un concept prenant effet dans une unité de traduction. Lorsque plusieurs compilations sont impliquées, le lien commence à se produire.

Si vous déclarez la variable d'étendue de fichier static, elle indique la liaison interne de la variable, ce qui signifie qu'elle n'est pas visible en dehors de cette unité de traduction.Si vous ne le déclarez pas explicitement, ou si vous déclarez la variable de portée de fichier extern, il est visible aux autres unités de traduction: celles qui déclarent une variable de portée de fichier avec le même identificateur auront cet identifiant liera à cette même variable.

Dans votre cas, l'inclusion de bar.c dans foo.c insère la définition de fileScopeVariable dans l'unité de traduction en cours de compilation. Ainsi, il est visible dans cette unité.

2

Ne pas jamais #include un fichier .c comme vous le faites ici. Le langage le permet, mais les codeurs C ne le font pas, alors vous allez confondre les gens si vous le faites. Très probablement, y compris vous-même. "#include" signifie "Compilateur, veuillez aller dans cet autre fichier et le coller au début de celui-ci avant de commencer à compiler mon code."

Une fois, j'ai perdu une journée entière dans la confusion totale, car l'un des fichiers sources de vxWorks l'a fait. Je suis toujours guidé vers eux.

+0

Merci, je comprends maintenant. :-) – Metaphile

+0

Qu'est-ce que "PO at them"? – ziyuang

+0

Je crois en un avenir où les fichiers d'en-tête disparaîtront complètement de c, car ils ont déjà quitté tous les langages de programmation moderne sain. Ils n'existent que parce que C n'a aucun moyen de contrôler la portée des typedefs et des macros inclus dans l'en-tête. C doit rendre les macros uniquement visibles dans la portée où elles sont déclarées, comme le font déjà typedefs. Les en-têtes sont LA raison pour laquelle la plupart des codes C sont incompréhensibles: les inclusions redondantes rendent très difficile le suivi du flux de contrôle, et qui comprend quoi, et toutes les portées sont contaminées par des définitions globales et des typedefs non pertinentes. – Dmitry