147 votes

Placement des déclarations de variables en C

J'ai longtemps pensé qu'en C, toutes les variables devaient être déclarées au début de la fonction. Je sais qu'en C99, les règles sont les mêmes qu'en C++, mais quelles sont les règles de placement des déclarations de variables en C89/ANSI C ?

Le code suivant se compile avec succès avec gcc -std=c89 y gcc -ansi :

#include <stdio.h>
int main() {
    int i;
    for (i = 0; i < 10; i++) {
        char c = (i % 95) + 32;
        printf("%i: %c\n", i, c);
        char *s;
        s = "some string";
        puts(s);
    }
    return 0;
}

Les déclarations de c y s provoque une erreur en mode C89/ANSI ?

63 votes

Juste une remarque : les variables en C ansi ne doivent pas être déclarées au début d'une fonction mais plutôt au début d'un bloc. Ainsi, char c = ... au début de votre boucle for est tout à fait légal en ansi C. Le char *s, cependant, ne le serait pas.

176voto

mipadi Points 135410

Il compile avec succès parce que GCC permet la déclaration de s comme une extension GNU, même si elle ne fait pas partie de la norme C89 ou ANSI. Si vous voulez adhérer strictement à ces normes, vous devez passer le test de l'extension -pedantic drapeau.

La déclaration de c au début d'un { } fait partie de la norme C89 ; le bloc ne doit pas nécessairement être une fonction.

46 votes

Il est probablement utile de noter que seule la déclaration de s est une extension (du point de vue de C89). La déclaration de c est parfaitement légal en C89, aucune extension n'est nécessaire.

8 votes

@AndreyT : Oui, en C, les déclarations de variables doivent être au début d'un fichier bloc et non une fonction en soi ; mais les gens confondent bloc et fonction car c'est le principal exemple de bloc.

1 votes

J'ai déplacé le commentaire avec +39 votes dans la réponse.

83voto

Kiley Hykawy Points 411

En C89, vous devez déclarer toutes vos variables au début d'un fichier de type bloc de contrôle .

Donc, votre char c est valide car elle se trouve en haut du bloc de portée de la boucle for. Mais, le bloc char *s devrait être une erreur.

3 votes

Tout à fait correct. Vous pouvez déclarer des variables au début de tout { ... }.

6 votes

@Artelius Pas tout à fait correct. Seulement si les boucles font partie d'un bloc (pas si elles font partie d'une déclaration de structure ou d'union ou d'un initialisateur entre accolades).

0 votes

Juste pour être pédant, la déclaration erronée devrait au moins être notifiée selon la norme C. Il devrait donc y avoir une erreur ou un avertissement en gcc . En d'autres termes, ne croyez pas que le fait qu'un programme puisse être compilé signifie qu'il est conforme.

48voto

MarcH Points 1868

Le regroupement des déclarations de variables en haut du bloc est un héritage probablement dû aux limitations des anciens compilateurs C primitifs. Tous les langages modernes recommandent et parfois même imposent la déclaration des variables locales au dernier moment : là où elles sont initialisées pour la première fois. En effet, cela élimine le risque d'utiliser une valeur aléatoire par erreur. Séparer la déclaration et l'initialisation vous évite également d'utiliser "const" (ou "final") quand vous le pourriez.

Malheureusement, le C++ continue d'accepter l'ancienne méthode de déclaration supérieure pour assurer la compatibilité avec le C (un problème de compatibilité avec le C parmi tant d'autres...) Mais le C++ essaie de s'en éloigner :

  • La conception des références C++ ne permet même pas un tel regroupement en haut du bloc.
  • Si vous séparez la déclaration et l'initialisation d'un fichier local C++ objet alors vous payez le coût d'un constructeur supplémentaire pour rien. Si le constructeur sans argument n'existe pas, vous n'êtes même pas autorisé à séparer les deux !

C99 commence à déplacer C dans cette même direction.

Si vous craignez de ne pas trouver l'endroit où sont déclarées les variables locales, cela signifie que vous avez un problème bien plus important : le bloc qui l'entoure est trop long et doit être divisé.

https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimiser+la+portée+des+variables+et+des+fonctions

1 votes

0 votes

Voyez également comment le fait de forcer les déclarations de variables en haut du bloc peut créer des failles de sécurité : lwn.net/Articles/443037

0 votes

"Malheureusement, le C++ continue d'accepter l'ancienne méthode de déclaration par le haut pour assurer la compatibilité avec le C" : à mon avis, c'est la façon la plus propre de le faire. D'autres langages "résolvent" ce problème en initialisant toujours avec 0. Bzzt, cela ne fait que masquer des erreurs de logique si vous voulez mon avis. Et il y a pas mal de cas où vous avez BESOIN d'une déclaration sans initialisation parce qu'il y a plusieurs emplacements possibles pour l'initialisation. Et c'est pourquoi le RAII de C++ est vraiment une énorme douleur dans le cul - Maintenant vous devez inclure un état non initialisé "valide" dans chaque objet pour permettre ces cas.

24voto

Adam Liss Points 27815

Du point de vue de la maintenabilité, plutôt que de la syntaxe, il existe au moins trois pistes de réflexion :

  1. Déclarez toutes les variables au début de la fonction afin qu'elles se trouvent au même endroit et que vous puissiez voir la liste complète d'un seul coup d'œil.

  2. Déclarez toutes les variables aussi près que possible de l'endroit où elles sont utilisées pour la première fois, afin que vous sachiez por qué chacun est nécessaire.

  3. Déclarez toutes les variables au début du bloc de portée le plus interne, afin qu'elles sortent de leur portée dès que possible et que le compilateur puisse optimiser la mémoire et vous prévenir si vous les utilisez accidentellement là où vous ne l'aviez pas prévu.

Je préfère généralement la première option, car je trouve que les autres m'obligent souvent à chercher les déclarations dans le code. Définir toutes les variables à l'avance permet également de les initialiser et de les observer plus facilement depuis un débogueur.

Il m'arrive parfois de déclarer des variables à l'intérieur d'un bloc plus petit, mais uniquement pour une bonne raison, dont j'ai très peu. Un exemple pourrait être après un fork() pour déclarer les variables nécessaires uniquement au processus enfant. Pour moi, cet indicateur visuel est un rappel utile de leur but.

32 votes

J'utilise l'option 2 ou 3 pour qu'il soit plus facile de trouver les variables - car les fonctions ne doivent pas être si grandes que l'on ne puisse pas voir les déclarations de variables.

8 votes

L'option 3 n'est pas un problème, sauf si vous utilisez un compilateur des années 70.

17 votes

Si vous utilisiez un IDE décent, vous n'auriez pas besoin d'aller à la chasse au code, car il devrait y avoir une commande IDE pour trouver la déclaration pour vous. (F3 dans Eclipse)

9voto

Gaidheal Points 31

Comme l'ont noté d'autres personnes, GCC est permissif à cet égard (et peut-être d'autres compilateurs, selon les arguments avec lesquels ils sont appelés) même en mode 'C89', à moins que vous n'utilisiez une vérification 'pédante'. Pour être honnête, il n'y a pas beaucoup de bonnes raisons de ne pas utiliser la vérification pédante ; un code moderne de qualité devrait toujours compiler sans avertissement (ou très peu lorsque vous savez que vous faites quelque chose de spécifique qui est suspect pour le compilateur comme une erreur possible), donc si vous ne pouvez pas faire compiler votre code avec une configuration pédante, il a probablement besoin d'attention.

La C89 exige que les variables soient déclarées avant toute autre instruction dans chaque champ d'application. Les normes ultérieures permettent une déclaration plus proche de l'utilisation (ce qui peut être à la fois plus intuitif et plus efficace), notamment la déclaration et l'initialisation simultanées d'une variable de contrôle de boucle dans les boucles 'for'.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X