2008-11-16 21 views
8

Lo siento por la nueva pregunta. Todavía estoy aprendiendo programación. Así que estoy usando C++, y tengo que hacer algo como esto:La construcción de lazo más elegante?

int n; 
do { 
    n = get_data(); 
    if(n != -1) 
     send(n); 
} while(n != -1); 

Esto es solo un boceto. De todos modos, no se siente realmente elegante. Tengo que tener mi prueba dos veces. Podría simplemente probar una vez y establecer una bandera, pero eso tampoco parece realmente elegante ya que tengo que revisar la bandera dos veces. Simplemente parece que debería haber una manera de hacer esto más fácilmente, ya que es muy fácil lo que quiero hacer.

+1

Honestamente, encuentro tu código fácil de leer. Pasar el tiempo haciéndolo más corto (y más tiempo para desempaquetarlo en la cabeza cuando lo leerá nuevamente) no es la mejor inversión que puede hacer. A quién le importa: funciona, es eficiente y legible. Ir a las siguientes líneas –

Respuesta

15

Howabout usando break:

int n; 
while(1) { 
    n = get_data(); 
    if(n == -1) 
     break; 
    send(n); 
} 

De esta manera sólo prueba una vez, y dejar de fumar inmediatamente si get_data no devuelve lo que quiere.

+0

Lo prefiero porque es muy expresivo y escala incluso cuando get_data() se vuelve más complejo. En ese caso, también agregaría un comentario que describa la condición de salida al "bucle eterno", p. Ej. // se rompe cuando get_data() == -1. – peterchen

+0

Esta es una instancia de la bien conocida construcción "Loop and a Half": http://www.cs.duke.edu/~ola/patterns/plopd/loops.html#loop-and-a-half –

+0

The más obvio y, por lo tanto, el más elegante que cuenta para mí. –

19
int n; 
while (-1 != (n = get_data())) { 
    send(n); 
} // while 
+7

Desprecio cuando las personas ponen la constante en el lado izquierdo de la comparación. – SoapBox

+0

Algunos de mis antiguos colegas se sienten ofendidos por este constructo (el efecto secundario incrustado en la expresión condicional) y varios libros de texto te dicen que no hagas eso. Aunque nunca entendí por qué, creo que está bien, pero a veces es mejor evitarlo por razones políticas. – finnw

+4

Coloque la constante a la izquierda para que sea un error de compilación cuando accidentalmente cambie == o! = Al operador de asignación (=). Esto ya no es un problema en la mayoría de los lenguajes modernos, especialmente con los IDEs modernos. Todavía lo hago en código C++. –

4

Su versión original está bien.

En mi último trabajo de programación C tuvimos que seguir los estándares de codificación MISRA.

Bajo las reglas Misra, esto:

int n; 
while(1) { 
    n = get_data(); 
    if(n == -1) 
     break; 
    send(n); 
} 

está prohibido debido a la break, y esto:

while((n = get_data()) != -1) { send(n); } 

está prohibido debido a una asignación aparece en un contexto booleano, así que estoy en el hábito de escribir bucles similares a su versión original.

Usted podría una variable booleana si usted piensa que hará que su intención más clara o si la prueba es una expresión compleja:

int n; 
bool valid; 
do { 
    n = get_data(); 
    valid = n != -1; 
    if(valid) 
     send(n); 
} while(valid); 

Pero para una prueba simple como "n != -1" puede que no sea la pena hacer el programa más largo.

+1

No pude encontrar una versión en línea de ese estándar MISRA (aunque puedes comprar un libro por $ 25 ...). Según su descripción, se siente un poco estúpido, imponiendo un estilo de codificación voluminoso al programador. – Svante

+0

Además, eche un vistazo a http://www.knosof.co.uk/misracom.html – Svante

+0

@ Harleqin, tiene razón, el código resultante puede ser voluminoso, algunas de las reglas son excesivas, y algunas otras no lo hacen Tiene sentido fuera de las plataformas integradas. – finnw

17

similares a eed3si9n de, pero sin duda más fácil de leer:

int n; 
while (n = get_data(), n != -1) 
{ 
    send(n); 
} 
+0

Tendría que argumentar en contra de que sea más fácil de leer. La mayoría de los programadores no entienden el operador de coma en C y tropiezan con este tipo de constructo. – JaredPar

+0

Por otro lado, muchos programadores también tienen dificultades con el hecho de que operator = devuelve el valor asignado, y su uso puede conducir fácilmente a errores como se menciona en otros lugares. Pero es por eso que dije "discutible" en lugar de "definitivamente" :-) – SCFrench

+0

Incluso si su familiaridad con la coma es deficiente, esta versión se ve mucho más limpia. Siento que alguien que lo vio pero que no estaba acostumbrado a las comas aún podría analizar esto más rápido que la versión de eed3si9n. – Brian

11
for (int n = get_data(); n != -1; n = get_data()) { 
    send(n); 
} 
+0

Definitivamente la mejor/más clara solución para esto. –

+0

Quita las llaves si quieres guardar una línea :) – Jonathan

+0

Sí, si quieres acortarla (cosa que no hago), esta sería la mejor manera. A, al menos, uso inteligente del bucle for. –

0

construcción con un goto :)

int n; 
goto inside; do { 
    send(n); 
inside: 
    n=get_data(); 
} while(n!=-1); 
+0

No hay diferencia entre un ciclo do y un ciclo while si nunca lo ingresas desde arriba, ¿verdad? Si no, usaría la forma más familiar de 'while'. – finnw

+0

Sí, tienes razón, no hay diferencia real. Es solo una cuestión de gusto personal :) Me gustó la forma do-while porque las líneas con la obtención de datos y la línea con una prueba sobre estos datos (condición de ciclo) residen una tras otra. – lazyden

+0

Normalmente votaría esto porque el formato dificulta la lectura, pero es un enfoque interesante. – EvilTeach

-2
int get_data() 
{ 
... 
} 

void _send(int) 
{ 
... 
} 

int send(int (*a)()) 
{ 
    int n = a(); 

    if (n == -1) 
     return n; 

    _send(n); 
    return 1; 
} 

int main() 
{ 
    int (*fp)(); 
    fp = get_data; 
    while (send(fp)!= -1); 

    return 0; 
} 

HTH

+1

+1 para un enfoque muy diferente. – EvilTeach

1
int n; 
n = get_data(); 
while (n != -1) { 
    send(n); 
    n = get_data(); 
} 
+0

Esta es la forma en que se les enseñó a hacer bucles en cobol, hace mucho tiempo. ¿Un compilador típico tiende a compilar esto en una forma eficiente? De lo que he visto, la solución de lazydens es típicamente lo que generará un compilador para aumentar la eficiencia de la caché de instrucciones – EvilTeach

0

En Python que podría hacer esto:

while True: 
    n = get_data() 
    if n == -1: 
     break 
    send(n) 

Como se puede ver, esto no es mucho más corta que la versión C. Normalmente, un código Python es de 5 a 10 veces más pequeño que su equivalente en C. Este no es el caso aquí, por lo que puede disfrutar de su fragmento de texto legible, suficientemente corto y rápido, y centrarse en otra cosa.

Si quiere acortarlo, consulte la respuesta de Jonathan, pero realmente esto no importa.

2
/* This is cleaner */ 
AGAIN:; 
    int n = get_data(); 
    if (n != -1) 
    { 
     send(n); 
     goto AGAIN; 
    } 


/* This has some charm as well */ 
int n; 
while ((n = get_data()) != -1) 
    send(n); 
/* and now i see that this is the top answer. Oh well */ 
Cuestiones relacionadas