Ante todo:
Un do-while
bucle no es lo mismo que un while
bucle o un for
bucle.
while
y los for
bucles pueden no ejecutar el cuerpo del bucle en absoluto.
- Un
do-while
bucle siempre ejecuta el cuerpo del bucle al menos una vez; omite la verificación de condición inicial.
Entonces esa es la diferencia lógica. Dicho esto, no todos se adhieren estrictamente a esto. Es bastante común que se utilicen bucles for while
o for
incluso cuando se garantiza que siempre se repetirá al menos una vez. (Especialmente en idiomas con bucles foreach ).
Entonces, para evitar comparar manzanas y naranjas, procederé asumiendo que el ciclo siempre se ejecutará al menos una vez. Además, no volveré a mencionar los for
bucles, ya que son esencialmente while
bucles con un poco de azúcar de sintaxis para un contador de bucles.
Entonces estaré respondiendo a la pregunta:
Si while
se garantiza que un bucle se repita al menos una vez, ¿hay alguna ganancia de rendimiento al usar un do-while
bucle en su lugar?
A do-while
omite la primera comprobación de condición. Entonces, hay una rama menos y una condición menos para evaluar.
Si la condición es costosa de verificar y sabe que tiene la garantía de realizar un bucle al menos una vez, entonces un do-while
bucle podría ser más rápido.
Y aunque esto se considera una microoptimización en el mejor de los casos, es una que el compilador no siempre puede hacer: específicamente cuando el compilador no puede probar que el bucle siempre entrará al menos una vez.
En otras palabras, un ciclo while:
while (condition){
body
}
Es efectivamente lo mismo que esto:
if (condition){
do{
body
}while (condition);
}
Si sabe que siempre hará un bucle al menos una vez, esa instrucción if es extraña.
Del mismo modo, a nivel de ensamblaje, así es aproximadamente como se compilan los diferentes bucles para:
bucle de hacer mientras:
start:
body
test
conditional jump to start
bucle while:
test
conditional jump to end
start:
body
test
conditional jump to start
end:
Tenga en cuenta que la condición se ha duplicado. Un enfoque alternativo es:
unconditional jump to end
start:
body
end:
test
conditional jump to start
... que cambia el código duplicado por un salto adicional.
De cualquier manera, sigue siendo peor que un do-while
bucle normal .
Dicho esto, los compiladores pueden hacer lo que quieran. Y si pueden demostrar que el bucle siempre entra una vez, entonces ha hecho el trabajo por usted.
Pero las cosas son un poco extrañas para el ejemplo particular de la pregunta porque tiene un cuerpo de bucle vacío. Como no hay cuerpo, no hay diferencia lógica entre while
y do-while
.
FWIW, probé esto en Visual Studio 2012:
Con el cuerpo vacío, en realidad genera el mismo código para while
y do-while
. Así que esa parte probablemente sea un remanente de los viejos tiempos cuando los compiladores no eran tan buenos.
Pero con un cuerpo no vacío, VS2012 logra evitar la duplicación del código de condición, pero aún genera un salto condicional adicional.
Así que es irónico que, si bien el ejemplo de la pregunta resalta por qué un do-while
bucle podría ser más rápido en el caso general, el ejemplo en sí no parece ofrecer ningún beneficio en un compilador moderno.
Teniendo en cuenta la antigüedad del comentario, solo podemos adivinar por qué sería importante. Es muy posible que los compiladores en ese momento no fueran capaces de reconocer que el cuerpo estaba vacío. (O si lo hicieron, no usaron la información).