2009-08-07 11 views
21

Solo una pregunta rápida.evaluación de condición de lazo

que tienen un bucle que tiene este aspecto:

for (int i = 0; i < dim * dim; i++) 

es la condición en un bucle for re-evaluado en cada circuito?

Si es así, ¿sería más eficiente para hacer algo como esto ?:

int dimSquare = dim * dim; 
for (int i = 0; i < dimSquare; i++) 

Gracias

-Faken

Respuesta

32

En general, si por ejemplo cambia el valor de "dim" dentro de su ciclo, se volvería a evaluar cada vez. Pero dado que ese no es el caso en su ejemplo, un compilador decente optimizaría su código y no vería ninguna diferencia en el rendimiento.

+0

Perdóneme por la persona con una respuesta muy larga y pensada, pero esta respuesta me explicó todo de una manera clara y concisa. – Faken

+3

Pero no olvide tomar en serio la sugerencia de bdonlan sobre el uso de variables locales para control de bucle: los lugareños facilitan las cosas para que los compiladores optimicen su visibilidad (esto también puede ayudar a la comprensión del lector, no solo a la optimización del compilador). –

+0

No me disculparía si fuera tú. Esto le da a bdonlan una oportunidad decente de la insignia "populista", con 9 votos más (al momento de escribir) y si Lulu obtiene 8 :-) –

-4

el compilador calcular previamente el valor de Dim Dim * antes del bucle comienza

+0

A menos que se pueda modificar Dim dentro del ciclo. –

+0

entonces, ¿qué dice usted que en un ciclo for, incluso si el valor de dim cambia durante el ciclo, el ciclo se ejecutará hasta que se alcance el valor precompilado? ¿O el programa volverá a evaluarlo cuando los cambios de intensidad aparezcan en la mitad del ciclo? – Faken

+1

@Faken, si hay alguna posibilidad de que cambie Dim, el compilador lo volverá a evaluar _every_ loop. – bdonlan

44

Sí, semánticamente se evaluará en cada ciclo. En algunos casos, compiladores pueden ser capaces de eliminar la condición del bucle automáticamente, pero no siempre. En particular:

void foo(const struct rect *r) { 
    for (int i = 0; i < r->width * r->height; i++) { 
    quux(); 
    } 
} 

El compilador no será capaz de mover la multiplicación en este caso, en cuanto a todo lo que sabe quux() modifica r.

En general, generalmente solo las variables locales son elegibles para el levantamiento de expresiones de un bucle (¡suponiendo que nunca tome su dirección!). Si bien, bajo ciertas condiciones, los miembros de la estructura también pueden ser elegibles, hay muchas cosas que pueden hacer que el compilador suponga que todo en la memoria ha cambiado, por ejemplo, escribir en cualquier puntero o invocar prácticamente cualquier función. Por lo tanto, si utiliza usuarios no locales, es mejor asumir que la optimización no ocurrirá.

Dicho esto, en general, yo recomiendo única forma proactiva moviendo el código potencialmente costosa de la condición si, sea:

  • no hace daño a la legibilidad de hacerlo
  • Obviamente tendrá un muy long time (por ejemplo, acceso a la red)
  • O aparece como un punto de acceso en el perfilado.
+6

Tenga en cuenta que r podría ser 'const struct rect *' en su ejemplo, y el compilador * todavía * no podría suponer que quux() no modifica de alguna manera sus miembros de datos mediante un alias. Comúnmente se supone que const activa todo tipo de optimizaciones del compilador, pero no es tan simple como uno podría pensar primero. –

+0

@onebyone: De hecho. Restrict podría ayudar aquí, sin embargo. – bdonlan

+0

Sí, para los compiladores C++ que también son compiladores C99 y, por lo tanto, admiten restricción. Y las reglas de alias estrictas ayudan a "escribir casi cualquier puntero", pero no a "llamar virtualmente a ninguna función". Inline debe ayudar con las funciones. –

Cuestiones relacionadas