En mi proyecto actual, que usa el estándar MISRA 2004, usamos tres compiladores GCC, versiones 3.2.3, 4.4.2 y 5.4.0.
Realizamos verificaciones de compilación con el interruptor pedante y el estándar c89 y muchas otras restricciones. Una de las restricciones es que todos los datos deben inicializarse en la declaración.
Tengo un problema porque en GCC 3.2.3, el inicializador de cero universal {0} solo se compila para matrices de tipos unitarios básicos. Si tengo una matriz de estructuras, recibo una advertencia de llaves faltantes y la advertencia solo desaparece si cambio {0} por {{0}} .
struct my_type my_thing[NUMBER_OF_THINGS] = {0};se convierte
struct my_type my_thing[NUMBER_OF_THINGS] = {{0}};Sin embargo, esto no funciona para arreglos de estructuras que tienen miembros de estructura. Entonces el problema está en el compilador 4.4.2, que da errores de inicialización faltantes, así que tuve que hacer esto:
struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};Esto satisface a los compiladores, pero hace tropezar a nuestro verificador MISRA, porque MISRA exige el inicializador único universal {0} o el inicializador completo de matriz completa:
struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}, {0, 0, {0}, 0}, {0, 0, {0}, 0}, {0, 0, {0}, 0}, {0, 0, {0}, 0}}; Esto no es práctico para nosotros porque tenemos todo tipo de restricciones y NUMBER_OF_THINGS puede modificarse y generarse automáticamente desde fuera del código fuente en el momento de la compilación.
Me gustaría poder decirle a mi jefe que el llamado inicializador universal {0} es suficiente para inicializar cualquier matriz. He encontrado hilos en las listas de correo de GCC y Bugzilla, desde hace muchos años, que consideran que las advertencias del compilador que he mencionado son errores y afirman que {0} es parte del estándar. Sin embargo, ninguno de ellos menciona qué estándar, y no he podido encontrar {0} en los borradores ISO C89 o C99, o K&R v2. ¿Es el {0} un estándar? ¿ Hay alguna forma de garantizar que una matriz de estructuras con miembros de estructura se inicialice en ceros (o NULL)?
El problema es que, si bien puedo eliminar mágicamente las violaciones del código MISRA, no estoy seguro de que al hacer esto:
struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};... es suficiente para garantizar que la matriz se pondrá a cero por completo.
¿Puede alguien ofrecer sabiduría desde la raíz de este problema?
El inicializador {0} para inicializar todos los objetos en un agregado (es decir, matriz o estructura) es 100 % estándar en cualquier versión de C. La sintaxis le permite omitir las llaves para los subagregados.
No entraré en todos los detalles sucios aquí. En caso de que esté interesado en el texto normativo formal, esto se explica en una serie de reglas complejas sobre las que puede leer, por ejemplo, en C11 6.7.9 desde §17 en adelante.
Con respecto a MISRA-C:2004, esta regla era un poco engorrosa y existe un MISRA-C:2004 TC1 al respecto. Es posible que su analizador estático no implemente correctamente TC1 9.2, que establece que {0} en el nivel superior es compatible.
Aún así, el TC1 no resolvió todas las cosas. Le pregunté al comité sobre esto en 2008 aquí:
https://www.misra.org.uk/forum/viewtopic.php?f=65&t=750
La respuesta que obtuve allí es una respuesta formal del comité y puede usarse como referencia en su documentación. El comité acordó que la regla necesitaba mejoras adicionales y, en base a esto, la regla se corrigió en MISRA-C:2012, donde {0} se puede usar en cualquier lugar para inicializar subobjetos de tipo agregado.
Recomendaría usar MISRA-C:2012 si es posible.
Si. {0} también es un inicializador universal válido en C89 :
Si hay menos inicializadores en una lista que miembros de un agregado, el resto del agregado se inicializará implícitamente igual que los objetos que tienen una duración de almacenamiento estática.
También es cierto en todas las versiones más nuevas del estándar.
La advertencia que recibe de gcc es un error antiguo: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80454 que se solucionó alrededor de gcc 4.9.
Para tu situación, podrías considerar:
-Wno-missing-braces para silenciar la advertencia, ya que se trata de un error conocidomemset para inicializar sus tipos de estructuraEl "inicializador universal" {0} debería funcionar. Para C89, los párrafos relevantes de la sección 3.5.7 son:
De lo contrario, el inicializador para un objeto que tiene un tipo agregado será una lista de inicializadores entre llaves para los miembros del agregado, escrita en subíndice creciente o en orden de miembros; y el inicializador para un objeto que tiene tipo de unión será un inicializador entre llaves para el primer miembro de la unión.
Si el agregado contiene miembros que son agregados o uniones, o si el primer miembro de una unión es un agregado o unión, las reglas se aplican recursivamente a los subagregados o uniones contenidas. Si el inicializador de un subagregado o unión contenida comienza con una llave izquierda, los inicializadores encerrados por esa llave y su llave derecha coincidente inicializan los miembros del subagregado o el primer miembro de la unión contenida. De lo contrario, solo se tienen en cuenta suficientes inicializadores de la lista para los miembros del primer subagregado o el primer miembro de la unión contenida; los inicializadores restantes se dejan para inicializar el siguiente miembro del agregado del que forma parte el subagregado actual o la unión contenida.
Si hay menos inicializadores en una lista que miembros de un agregado, el resto del agregado se inicializará implícitamente igual que los objetos que tienen una duración de almacenamiento estática.