2008-10-10 7 views
14

Puede, por supuesto, poner una declaración de variable en un bucle for:¿Por qué no puedo poner una declaración de variable en la porción de prueba de un ciclo while?

for (int i = 0; ... 

y me he dado cuenta de que puede hacer lo mismo en el if y switch, así:

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

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

pero cuando trato de hacer lo mismo en un bucle while:

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

el compilador (VC++ 9.0) no le gusta en absoluto.

¿Es esto comportamiento obediente? ¿Hay alguna razón para ello?

EDITAR: He encontrado que puedo hacer esto:

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

pero debido a las reglas de prioridad, que ha interpretado como:

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

que no es lo que quiero.

+0

gcc no lo hace permítanme declarar una variable en la declaración "if", en realidad –

+0

¿No quiere decir mientras (int ch = (stream.get()! = -1)) en el último ejemplo? –

+0

como una opción para evitar esto, es posible que desee considerar el operador de coma: while (int ch, (ch = stream.get())! = -1) {// hacer cosas aquí} – workmad3

Respuesta

12

La gramática para una condición en la norma '03 se define como sigue:

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

Lo anterior por lo tanto sólo permitirá condiciones tales como:

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

La norma permite la condición de declarar una variable, sin embargo, lo han hecho al agregar una nueva regla de gramática llamada 'condición' que puede ser una expresión o un declarador con un inicializador. El resultado es que solo porque se encuentre en la condición de if, for, while o switch no significa que pueda declarar una variable dentro de una expresión.

+2

Derecha - la clave es que una declaración no es una expresión. –

2

Puede ser porque el contenido de la cláusula while se evalúa en cada ciclo, por lo que trataría de declarar "ch" varias veces.

Los ejemplos de if, switch y for loop que usted proporcionó tendrán una "ch" definida solo una vez.

10

Esto no parece ser un comportamiento compatible. 6.5.1.2 parte de los estados estándar:

Cuando la condición de una sentencia while es una declaración, el alcance de la variable que se declara extiende desde su punto de declaración (3.3.1) hasta el final de la declaración while. Una declaración mientras que de la forma

mientras declaración

(T = x t) es equivalente a

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

Así que en su ejemplo, ch debe ser declarado dentro del alcance del bucle y funciona correctamente (recreado a través de cada iteración de bucle). La razón del comportamiento observado probablemente se debe a que el compilador no analizó correctamente la variable y luego la declaró varias veces.

+0

El compilador cumple perfectamente, es imposible hacer lo que pregunta la pregunta. Ver mi respuesta a continuación. – Arkadiy

2

Usted puede poner una declaración de variable en la expresión de prueba de un ciclo while. Lo que no se puede hacer es poner una declaración en otras expresiones. Por ejemplo, en la expresión a + b + c, no puede reemplazar b por int i = f(). Y la misma espera para la expresión (a); no puede insertar int i=f() para obtener una expresión (int i=f()).

Por lo tanto, en while (int i = foo()), los paréntesis más externos son parte de la sentencia while, y no de la expresión de texto, y todo es legal. En while ((int i = foo())), los corchetes exteriores todavía forman parte de la sentencia while.La expresión de prueba tendría el formato "(" expr ")" y terminaría con un error de sintaxis.

+0

No entiendo 'In while ((int i = foo())), los paréntesis más externos siguen siendo parte de la sentencia while. La expresión de prueba tendrá la forma "(" expr ")", y terminará con un error de sintaxis., Especialmente la última oración en para, explique con un mejor ejemplo? , muchas gracias :) –

+0

Lo que entendí es que puedo declarar la variable x en, por ejemplo, 'while (int x = ...)' pero la parte del inicializador i.e '...' debe contener la expresión no ninguna declaración, ¿verdad? –

+0

@ Mr.Anubis: No puede usar '(())' porque el interno '()' es una expresión, y no puede tener una declaración dentro de eso. Los '(') externos pertenecen al 'while' y no forman una expresión. Y sí, el inicializador para 'x' debe ser una expresión válida en sí misma, y ​​no puede contener una segunda declaración. – MSalters

0

Trate Esto no funciona

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

nunca he intentado pero si el comentario en su edición es correcta, esto debería funcionar.
VS 2005 ni siquiera lo compilará.

+0

Este código es interpretado por el compilador como: int ch = (stream.get(), ch! = -1) –

+0

Según mis fuentes, el operador de coma está en la parte inferior de la escala de precedencia, pero hay algo más roto con mi construcción. –

9

El problema es que el nivel de calidad que permite una declaraciónentre paréntesis. Lo que quiere hacer es obtener una declaración como parte de la expresión, que es algo que el estándar no le permitirá hacer.

mientras que() puede tener uno de dos sintaxis: while (< declaración >) o tiempo (< expresión >). La declaración usa "=", y se parece a la expresión, pero es una entidad sintáctica diferente.

Cuando se escribe

while(int i = 1) { 
} 

, que está perfectamente bien. "int i = 1" es una declaración. Sin embargo, lo que quiere es

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

Este es un animal muy diferente. Desea una expresión dentro de while(), donde uno de los términos de la expresión es una declaración. Ahora, la declaración es una declaración, y como tal no puede ser parte de la expresión. Es por eso que lo que debes hacer no se puede hacer.

(después de escribir toda la diatriba, me di cuenta de que otras 2 personas escribieron la misma cosa. Bueno, cuantos más, mejor. La respuesta aceptada sigue siendo incorrecto en el momento de mi escritura.)

Cuestiones relacionadas