2008-10-10 7 views
14

Vous pouvez, évidemment, mettre une déclaration variable dans une boucle:Pourquoi ne puis-je pas mettre une déclaration de variable dans la partie test d'une boucle while?

for (int i = 0; ... 

et je l'ai remarqué que vous pouvez faire la même chose si et passer des déclarations ainsi:

if ((int i = f()) != 0) ... 

switch (int ch = stream.get()) ... 

mais lorsque je tente de faire la même chose dans une boucle while:

while ((int ch = stream.get()) != -1) ... 

le compilateur (VC++ 9.0) ne l'aime pas du tout.

Est-ce que ce comportement est conforme? Y a-t-il une raison à cela?

EDIT: Je trouve que je peux faire ceci:

while (int ch = stream.get() != -1) ... 

mais à cause des règles de priorité, qui est interprété comme:

while (int ch = (stream.get() != -1)) ... 

qui est pas ce que je veux.

+0

gcc ne permettez-moi de déclarer une variable dans l'instruction "if" non plus, en fait –

+0

Ne voulez-vous pas dire while (int ch = (stream.get()! = -1)) dans le dernier exemple? –

+0

comme une option pour contourner cela, vous pouvez considérer l'opérateur de virgule: while (int ch, (ch = stream.get())! = -1) {// faire des choses ici} – workmad3

Répondre

12

La grammaire pour une condition dans la norme '03 est défini comme suit:

condition: 
    expression 
    type-specifier-seq declarator = assignment-expression 

ci-dessus permettra donc que des conditions telles que:

if (i && j && k) {} 
if ((i = j) ==0) {} 
if (int i = j) {} 

La norme permet la condition de déclarer une variable, cependant, ils l'ont fait en ajoutant une nouvelle règle de grammaire appelée 'condition' qui peut être une expression ou un déclarateur avec un initialiseur. Le résultat est que juste parce que vous êtes dans la condition d'un if, for, while, ou switch ne signifie pas que vous pouvez déclarer une variable dans une expression.

+2

Droite - la clé est qu'une déclaration n'est pas une expression. –

2

Il se peut que ce soit parce que le contenu de la clause while est évalué à chaque boucle, donc il essayera de déclarer "ch" plusieurs fois.

Les exemples de boucles if, switch et for que vous avez donnés auront tous "ch" défini une seule fois.

10

Cela ne semble pas être un comportement conforme. Une partie 6.5.1.2 des états standards:

Lorsque la condition d'une instruction while est une déclaration, la portée de la variable déclarée étend de son point de déclaration (3.3.1) à la fin de l'instruction while. Une déclaration while du formulaire

while (T t = x) Déclaration

équivaut à

label: 
{ //start of condition scope 
    T t = x; 
    if (t) { 
     statement 
     goto label; 
    } 
} 

Donc, dans votre exemple, ch doit être déclaré dans le cadre de la boucle et fonctionne correctement (avec elle étant recréée à travers chaque itération de boucle). La raison du comportement observé est probablement due au fait que le compilateur n'a pas correctement défini la variable, puis l'a déclarée plusieurs fois.

+0

Le compilateur est parfaitement conforme, il est impossible de faire ce que la question demande. Voir ma réponse ci-dessous. – Arkadiy

2

Vous peut mettre une déclaration de variable dans l'expression de test d'une boucle while. Ce que vous ne pouvez pas faire est de mettre une déclaration de déclaration dans d'autres expressions. Par exemple, dans l'expression a + b + c, vous ne pouvez pas remplacer b par int i = f(). Et la même prise pour l'expression (a); vous ne pouvez pas insérer int i=f() pour obtenir une expression (int i=f()). Donc, dans while (int i = foo()), les parenthèses les plus externes font partie de l'instruction while, et non de l'expression de texte, et tout est légal. Dans while ((int i = foo())), les parenthèses les plus externes font toujours partie de l'instruction while.L'expression de test aurait la forme "(" expr ")", et vous vous retrouvez avec une erreur de syntaxe.

+0

Je ne comprends pas 'Dans while ((int i = foo())), les parenthèses les plus externes font toujours partie de l'instruction while. L'expression de test aurait la forme "(" expr ")", et vous vous retrouvez avec une erreur de syntaxe. », Spécialement la dernière phrase de para, expliquer avec un meilleur exemple? , merci beaucoup :) –

+0

Ce que j'ai compris c'est que je peux déclarer la variable x dans while while 'while (int x = ...) 'mais la partie initializer i.e' ... 'doit contenir l'expression pas de déclaration, non? –

+0

@ Mr.Anubis: Vous ne pouvez pas utiliser '(())' car les internes '()' sont eux-mêmes une expression, et vous ne pouvez pas avoir de déclaration dedans. L'extérieur '()' appartient au 'while' et ne forme pas d'expression. Et oui, l'initialiseur de 'x' doit être lui-même une expression valide, et ne peut contenir une deuxième déclaration. – MSalters

0

Essayez Cela ne fonctionne pas

while (int ch = stream.get(), ch != -1) ... 

Je ne l'ai jamais essayé, mais si le commentaire dans votre édition est correcte, cela devrait fonctionner.
VS 2005 ne le compilera même pas.

+0

Ce code est interprété par le compilateur comme: int ch = (stream.get(), ch! = -1) –

+0

Selon mes sources, l'opérateur de virgule est au bas de l'échelle de priorité - mais il y a quelque chose d'autre qui est cassé avec ma construction. –

9

Le problème est, la norme vous permet une déclaration entre parenthèses. Ce que vous voulez faire, c'est obtenir une déclaration dans le cadre de l'expression, ce que la norme ne vous permet pas de faire. While() peut avoir l'une des deux syntaxes suivantes: while (< déclaration >) ou while (<expression>). La déclaration utilise "=" et ressemble à une expression, mais c'est une entité syntaxique différente.

Lorsque vous écrivez

while(int i = 1) { 
} 

, qui est tout à fait bien. "int i = 1" est une déclaration. Cependant, ce que vous voulez est

while ((int i = 1) + 3) { 
} 

Ceci est un animal très différent. Vous voulez une expression dans while(), où l'un des termes de l'expression est une déclaration. Maintenant, la déclaration est une déclaration, et en tant que telle ne peut pas faire partie de l'expression. C'est pourquoi ce que vous devez faire ne peut pas être fait.

(après avoir écrit toute diatribe, je remarquai que 2 autres personnes ont écrit la même chose. Eh bien, plus on est de fous. La réponse acceptée est toujours mal au moment de mon écriture.)

Questions connexes