Pardonnez si cette question est naïve. Considérez le programme suivant:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
Dans l'exemple ci-dessus, les instructions 5;
et i;
semblent totalement superflues, mais le code se compile sans avertissement ni erreur par défaut (cependant, gcc envoie un warning: statement with no effect [-Wunused-value]
avertissement lorsqu'il est exécuté avec -Wall
). Ils n'ont aucun effet sur le reste du programme, alors pourquoi sont-ils considérés comme des déclarations valables en premier lieu? Le compilateur les ignore-t-il simplement? Y a-t-il des avantages à autoriser de telles déclarations?
;
après. Cela compliquerait le langage d'ajouter plus de règles sur le moment où les expressions ne peuvent pas être des déclarationsprintf()
? L'instruction5;
dit essentiellement "faire tout ce qui5
fait (rien) et ignorer le résultat. Votre instructionprintf(...)
est" faire tout ce quiprintf(...)
fait et ignorer les résultats (la valeur de retour deprintf()
) ". C les traite de la même manière. Cela permet également d'utiliser du code tel que(void) i;
oùi
est un paramètre à une fonction que vous transformez pourvoid
le marquer comme délibérément inutiliséprintf()
a un effet, même si vous ignorez la valeur qu'il retourne finalement. En revanche,5;
n'a aucun effet.Réponses:
Un avantage à autoriser de telles déclarations provient du code créé par des macros ou d'autres programmes, plutôt que d'être écrit par des humains.
Par exemple, imaginez une fonction
int do_stuff(void)
qui est censée retourner 0 en cas de succès ou -1 en cas d'échec. Il se pourrait que la prise en charge de "stuff" soit facultative, et vous pourriez donc avoir un fichier d'en-tête qui neImaginez maintenant du code qui veut faire des choses si possible, mais qui ne se soucie pas vraiment s'il réussit ou échoue:
Quand
STUFF_SUPPORTED
est 0, le préprocesseur étendra l'appelfunc2
à une instruction qui lit simplementet ainsi le passage du compilateur verra juste le genre de déclaration "superflue" qui semble vous déranger. Mais que faire d'autre? Si vous
#define do_stuff() // nothing
, alors le codefunc1
entrera en panne. (Et vous aurez toujours une instruction vide dansfunc2
laquelle se lit simplement;
, ce qui est peut-être encore plus superflu.) D'un autre côté, si vous devez réellement définir unedo_stuff()
fonction qui renvoie -1, vous pouvez encourir le coût d'un appel de fonction sans raison valable.la source
((void)0)
.assert
.Les instructions simples en C se terminent par un point-virgule.
Les instructions simples en C sont des expressions. Une expression est une combinaison de variables, de constantes et d'opérateurs. Chaque expression donne une valeur d'un certain type qui peut être affectée à une variable.
Cela dit, certains «compilateurs intelligents» pourraient en rejeter 5; et moi; déclarations.
la source
void
n'a aucune valeur.Les déclarations sans effet sont autorisées car il serait plus difficile de les interdire que de les autoriser. Cela était plus pertinent lorsque C a été conçu pour la première fois et que les compilateurs étaient plus petits et plus simples.
Une instruction d'expression se compose d'une expression suivie d'un point-virgule. Son comportement consiste à évaluer l'expression et à ignorer le résultat (le cas échéant). Normalement, le but est que l'évaluation de l'expression ait des effets secondaires, mais il n'est pas toujours facile ni même possible de déterminer si une expression donnée a des effets secondaires.
Par exemple, un appel de fonction est une expression, donc un appel de fonction suivi d'un point-virgule est une instruction. Cette déclaration a-t-elle des effets secondaires?
Il est impossible de dire sans voir la mise en œuvre de
some_function
.Que dis-tu de ça?
Probablement pas - mais si
obj
est défini commevolatile
, alors c'est le cas.Permettre à toute expression d'être transformée en une expression-expression en ajoutant un point-virgule rend la définition du langage plus simple. Exiger que l'expression ait des effets secondaires ajouterait de la complexité à la définition du langage et au compilateur. C est construit sur un ensemble cohérent de règles (les appels de fonction sont des expressions, les affectations sont des expressions, une expression suivie d'un point-virgule est une instruction) et permet aux programmeurs de faire ce qu'ils veulent sans les empêcher de faire des choses qui peuvent ou non avoir du sens.
la source
Les instructions que vous avez répertoriées sans effet sont des exemples d'une instruction d'expression , dont la syntaxe est donnée dans la section 6.8.3p1 de la norme C comme suit:
Toute la section 6.5 est consacrée à la définition d'une expression, mais en gros, une expression se compose de constantes et d'identificateurs liés à des opérateurs. Notamment, une expression peut contenir ou non un opérateur d'affectation et elle peut ou non contenir un appel de fonction.
Ainsi, toute expression suivie d'un point-virgule peut être considérée comme une instruction d'expression. En fait, chacune de ces lignes de votre code est un exemple de déclaration d'expression:
Certains opérateurs contiennent des effets secondaires tels que l'ensemble des opérateurs d'affectation et les opérateurs d'incrémentation / décrémentation pré / post, et l'opérateur d'appel de fonction
()
peut avoir un effet secondaire en fonction de ce que fait la fonction en question. Il n'est cependant pas obligatoire que l'un des opérateurs ait un effet secondaire.Voici un autre exemple:
C'est appeler une fonction et ignorer le résultat, tout comme l'appel
printf
dans votre exemple, mais contrairement àprintf
l'appel de fonction lui-même n'a pas d'effet secondaire.la source
Parfois, de telles déclarations sont très utiles:
Ou lorsque le manuel de référence nous dit de simplement lire les registres pour archiver quelque chose - par exemple pour effacer ou définir un indicateur (situation très courante dans le monde uC)
https://godbolt.org/z/6wjh_5
la source
*SREG
est volatile,*SREG;
n'a aucun effet dans le modèle spécifié par la norme C. La norme C spécifie qu'il a un effet secondaire observable.