Supongamos que tengo un bucle for y una estructura muy grande como variable de pila:
for (int x=0 ; x <10; x++) { MY_STRUCT structVar = {0}; …code using structVar… } ¿Todos los compiladores realmente pondrán a cero la estructura al comienzo de cada ciclo? ¿O necesito usar memset para ponerlo a cero?
Esta es una estructura muy grande y quiero asignarla en la pila, y necesito asegurarme de que todos sus miembros se pongan a cero al comienzo de cada iteración. Entonces, ¿necesito usar memset ?
Puedo inspeccionar manualmente el ejecutable que compilo, pero necesito asegurarme de que haya algún estándar para esto, o simplemente depende del compilador.
Tenga en cuenta que este código se compila. Estoy usando Visual Studio.
¿Todos los compiladores realmente pondrán a cero la estructura al comienzo de cada ciclo?
Cualquier compilador que cumpla con el estándar C hará esto. De este Borrador C11 Estándar (el énfasis en negrita es mío):
6.8 Declaraciones y bloques
…
3 Un bloque permite agrupar un conjunto de declaraciones y sentencias en una unidad sintáctica. Los inicializadores de objetos que tienen duración de almacenamiento automático y los declaradores de matriz de longitud variable de identificadores ordinarios con ámbito de bloque se evalúan y los valores se almacenan en los objetos (incluido el almacenamiento de un valor indeterminado en objetos sin inicializador) cada vez que se realiza la declaración . alcanzado en el orden de ejecución , como si fuera una declaración, y dentro de cada declaración en el orden en que aparecen los declarantes.
En el caso de un ciclo for o while , una declaración/inicializador dentro del bloque de alcance del ciclo se alcanza repetidamente en todas y cada una de las iteraciones del ciclo.
¿Todos los compiladores realmente pondrán a cero la estructura al comienzo de cada bucle?
Sí, o producirá un código de máquina con una funcionalidad equivalente ("comportamiento observable") como si hubiera realizado una puesta a cero.
Siempre que inicialice un solo miembro en la estructura, el resto se establecerá en cero/nulo ("como si tuvieran una duración de almacenamiento estática"). De manera similar, cualquier byte de relleno agregado a la estructura por el compilador se establecerá en cero. Esto está garantizado por la norma C ISO:9899:2018 6.7.9 §10, §19 y §21.
Por lo general, el lugar donde realmente se produce la puesta a cero en el ejecutable resultante depende de cómo se utilicen los datos. Si, por ejemplo, pones a cero la estructura al comienzo del cuerpo del ciclo, luego escribes en varios miembros e imprimes todo al final del cuerpo del ciclo, el compilador no tiene muchas otras opciones más que poner a cero todo en cada vuelta. del bucle Ejemplo:
for (int x=0 ; x <10; x++) { MY_STRUCT structVar = {0}; ... structVar.foo = a; structVar.bar = b; printf("%d %d\n", structVar.foo, structVar.bar); } Por otro lado, el compilador podría en este caso ser lo suficientemente inteligente como para darse cuenta de que la estructura es solo un intermediario sin sentido y reemplazar todo esto con el equivalente printf("%d %d\n", a, b); , lo que significa que la estructura se eliminaría por completo del código de máquina.
En general, discutir optimizaciones como esta no se puede hacer sin un caso de uso específico, un compilador y un sistema de destino.
¿O necesito usar memset para ponerlo a cero?
No. MY_STRUCT structVar = {0}; es funcionalmente 100% equivalente a memset(structVar, 0, sizeof structVar); .
Esta es una estructura muy grande y quiero asignarla en la pila
Eso es un asunto diferente a la inicialización. De hecho, es imprudente asignar objetos grandes en la pila. En ese caso, considere reemplazarlo con, por ejemplo, esto:
MY_STRUCT* structVar = malloc(sizeof *structVar); for (int x=0 ; x <10; x++) { memset(structVar, 0, sizeof *structVar); ... } free(structVar);