#include <stdint.h> #define INIT_UINT32 1 #define INIT_INT32 2 #define INIT INIT_INT32 typedef union { uint32_t a; int32_t b; } Foo_t; /* Why does this compile... */ static Foo_t foo_static = INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }; /* but this doesn't? */ static Foo_t foo_static_array[] = { INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX } }; int main(void) { }Cuando se compila, la inicialización condicional de foo_static usando literales compuestos tiene éxito, pero falla la inicialización condicional de foo_static_array usando literales compuestos. Los siguientes son los errores de compilación.
$ gcc test.c test.c:4:21: error: initializer element is not constant 4 | #define INIT_INT32 2 | ^ test.c:6:14: note: in expansion of macro 'INIT_INT32' 6 | #define INIT INIT_INT32 | ^~~~~~~~~~ test.c:21:3: note: in expansion of macro 'INIT' 21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX } | ^~~~ test.c:4:21: note: (near initialization for 'foo_static_array[0]') 4 | #define INIT_INT32 2 | ^ test.c:6:14: note: in expansion of macro 'INIT_INT32' 6 | #define INIT INIT_INT32 | ^~~~~~~~~~ test.c:21:3: note: in expansion of macro 'INIT' 21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX } | ^~~~¿Alguien puede explicar por qué este es el caso?
GCC proporciona la inicialización anterior como una extensión del estándar C. No está proporcionando este último. Esta es una elección de GCC, no exigida por el estándar. Con -pedantic , GCC se queja de ambos.
El pasaje relevante en el estándar C es C 2018 6.7.9 4:
Todas las expresiones en un inicializador para un objeto que tiene una duración de almacenamiento estático o de subprocesos serán expresiones constantes o literales de cadena.
Esto está en una sección de Restricciones, lo que significa que un compilador conforme debe diagnosticarlo, como lo hace GCC cuando se usa -pedantic , aunque todavía acepta el código y completa la compilación. Sin -pedantic , GCC acepta ambos pero solo diagnostica el último.
La documentación de GCC sobre las extensiones C no dice nada sobre el motivo de esta diferencia. Su cláusula 6.27 dice que no se requiere que los inicializadores para agregados con duración de almacenamiento automático sean expresiones constantes, pero no hay una subcláusula en la cláusula de extensiones de C que aborde los inicializadores para objetos estáticos.
Para hacer que su código se ajuste estrictamente, no debe usar estos inicializadores en la inicialización sin arreglo o con arreglo.