¿Las variables de temperatura reducen la velocidad de mi progtwig?

Supongamos que tengo el siguiente código C:

int i = 5; int j = 10; int result = i + j; 

Si estoy repitiendo esto muchas veces, ¿sería más rápido usar int result = 5 + 10 ? A menudo creo variables temporales para hacer que mi código sea más legible, por ejemplo, si las dos variables se obtuvieron de alguna matriz usando alguna expresión larga para calcular los índices. ¿Esto es malo para el rendimiento en C? ¿Qué hay de otros idiomas?

Un comstackdor optimizador moderno debería optimizar esas variables, por ejemplo, si usamos el siguiente ejemplo en godbolt con gcc usando las -std=c99 -O3 ( ver en vivo ):

 #include  void func() { int i = 5; int j = 10; int result = i + j; printf( "%d\n", result ) ; } 

resultará en la siguiente asamblea:

 movl $15, %esi 

para el cálculo de i + j , esta es una forma de propagación constante .

Tenga en cuenta que agregué printf para que tengamos un efecto secundario, de lo contrario func se habría optimizado para:

 func: rep ret 

Estas optimizaciones están permitidas bajo la regla de si-si , que solo requiere que el comstackdor emule el comportamiento observable de un progtwig. Esto está cubierto en el borrador de la sección estándar C99 5.1.2.3 Ejecución del progtwig que dice:

En la máquina abstracta, todas las expresiones se evalúan según lo especificado por la semántica. Una implementación real no necesita evaluar parte de una expresión si puede deducir que su valor no se usa y que no se producen efectos secundarios necesarios (incluidos los causados ​​por llamar a una función o acceder a un objeto volátil).

Ver también: Optimización del código C ++: plegado constante

Esta es una tarea fácil de optimizar para un comstackdor de optimización. Eliminará todas las variables y reemplazará el result con 15 .

El plegado constante en forma de SSA es prácticamente la optimización más básica que existe.

El ejemplo que dio es fácil de optimizar para un comstackdor. El uso de variables locales para almacenar en caché los valores extraídos de estructuras y arreglos globales puede acelerar la ejecución de su código. Si, por ejemplo, está buscando algo de una estructura compleja dentro de un bucle for donde el comstackdor no puede optimizar y sabe que el valor no está cambiando, las variables locales pueden ahorrar bastante tiempo.

Puede usar GCC (otros comstackdores también) para generar el código de ensamblado intermedio y ver qué hace realmente el comstackdor.

Se discute cómo activar los listados de ensamblaje aquí: ¿Cómo usar GCC para producir un ensamblaje legible?

Puede resultar instructivo examinar el código generado y ver qué hace realmente un comstackdor.

Si bien todo tipo de diferencias triviales con el código pueden perturbar el comportamiento del comstackdor de maneras que mejoran o empeoran levemente el rendimiento, en principio no debería hacer ninguna diferencia en el rendimiento ya sea que utilice variables temporales como esta siempre que el significado del progtwig no sea cambiado Un buen comstackdor debe generar el mismo código o uno comparable de cualquier manera, a menos que esté construyendo intencionalmente con la optimización desactivada para obtener un código de máquina lo más cercano posible a la fuente (por ejemplo, con fines de depuración).

Usted está sufriendo el mismo problema que yo cuando trato de aprender lo que hace un comstackdor: crea un progtwig trivial para demostrar el problema y examina la salida de ensamblaje del comstackdor, solo para darse cuenta de que el comstackdor ha optimizado todo Trató de que desapareciera. Puede encontrar incluso una operación bastante compleja en main () reducida a esencialmente:

 push "%i" push 42 call printf ret 

Su pregunta original no es “¿qué ocurre con int i = 5; int j = 10... ?” pero “¿las variables temporales generalmente incurren en una penalización de tiempo de ejecución?”

La respuesta es probablemente no. Pero tendrías que mirar el resultado de ensamblaje para tu código particular, no trivial. Si su CPU tiene muchos registros, como un ARM, es probable que i y j estén en registros, exactamente como si esos registros estuvieran almacenando directamente el valor de retorno de una función. Por ejemplo:

 int i = func1(); int j = func2(); int result = i + j; 

es casi seguro que sea exactamente el mismo código de máquina que:

 int result = func1() + func2(); 

Sugiero que use variables temporales si hacen que el código sea más fácil de entender y mantener, y si realmente está tratando de ajustar un bucle, estará buscando en la salida del conjunto de todos modos para descubrir cómo perfeccionar tanto el rendimiento como posible. Pero no sacrifique la legibilidad y la capacidad de mantenimiento durante unos pocos nanosegundos, si eso no es necesario.