¿Puedo reducir una inicialización de matriz larga a una lista inicializadora corta en C?

Tengo un código C99 que se ve así:

struct foo { char* buf; size_t buf_sz; }; struct foo list[3]; list[0].buf = "The first entry"; list[0].buf_sz = strlen(list[0].buf); list[1].buf = "The second entry"; list[1].buf_sz = strlen(list[1].buf); list[2].buf = "The third entry"; list[2].buf_sz = strlen(list[2].buf); 

¿Hay una forma abreviada de escribir esto en una lista de inicializadores? ¿Es algo como esto seguro?

 struct foo list[] = { { "The first entry", strlen(list[0].buf) }, { "The second entry", strlen(list[1].buf) }, { "The third entry", strlen(list[2].buf) } }; 

Una alternativa sería:

 struct foo { char* buf; size_t buf_sz; }; ... struct foo list[] = { { "The first entry" }, { "The second entry" }, { "The third entry" } }; ... for ( int i = 0; i < sizeof(foo)/sizeof(foo[0]); i++ ) list[i].buf_sz = strlen(list[i].buf); // number of chars in string 

Si necesita poner el número de bytes reales consumidos por la cadena, entonces necesitará un +1 en su strlen . No sé lo que requiere la API.

Que tal este:

 #define S(str) { str, sizeof(str) - 1 } struct foo list[] = { S("The first entry"), ... }; #undef S 

I #undef ed la macro justo después del inicializador. Dichos nombres cortos deben usarse solo en un código compacto y corto. Si desea usarlo en otro lugar, use un nombre que se explique por sí mismo (debe incluir el nombre del tipo de struct ) y elimine el #undef .

Tenga en cuenta que esto solo funciona con una cadena literal. Pero funciona a nivel de archivo y no introduce ninguna sobrecarga en tiempo de ejecución. Por lo tanto, también funciona para const struct list[] , es decir, una matriz constante.

Tenga cuidado con el sizeof(str) - 1 . Esto es lo mismo que los rendimientos de strlen , pero la memoria asignada es en realidad sizeof(str) .

Tratar

 #define STR1 "The first entry" struct foo list[] = { {STR1, sizeof STR1}, ... 

Tenga en cuenta que el tamaño se establece en strlen(STR1) + 1 , debido al terminador 0 la “cadena”. Para ajustar esto haz

 struct foo list[] = { {STR1, sizeof STR1 - 1}, ... 

No puede usar su segunda definición para una matriz foo duración estática, ya que las listas de inicializadores para objetos de duración estática deben ser constantes. El borrador n1256 para los estados C99 en 6.7.8 Inicialización §4

4 Todas las expresiones en un inicializador para un objeto que tenga una duración de almacenamiento estática serán expresiones constantes o cadenas literales.

Incluso para las matrices foo automáticas (de ámbito de bloque) no está especificado por el estándar si su segunda syntax es válida o no está definida. El artículo §23 del mismo párrafo dice

23 El orden en que ocurren los efectos secundarios entre las expresiones de la lista de inicialización no se especifica.133)

y la nota 133 precisa:

En particular, el orden de evaluación no necesita ser el mismo que el orden de inicialización del subobjeto

Eso significa que sería aceptable para una implementación del comstackdor inicializar los miembros de buf_sz antes que los miembros de buf , lo que llevaría a UB (incluso si da un resultado correcto sin ninguna advertencia en mi antiguo MSVC2008).

Por estas razones, mi consejo es que inicialice solo los miembros de buf , y luego use un bucle para configurar los miembros de buf_sz que requieren que las estructuras ya estén inicializadas, como efecto secundario, si se puede usar para la duración del almacenamiento dynamic o estático:

 struct foo list[] = { { "The first entry" }, { "The second entry" }, { "The third entry" } }; 

y más tarde en el código:

 int i; for(i=0; i