How standard is the {0} initializer in C89?

喜欢而已 提交于 2020-08-22 03:00:21

问题


In my current project, which uses the MISRA 2004 standard, we use three GCC compilers, versions 3.2.3, 4.4.2 and 5.4.0.

We run build checks with the pedantic switch and c89 standard and a load of other restrictions. One of the restrictions is that all data must be initialised at declaration.

I have a problem in that on GCC 3.2.3, the universal zero initialiser {0} only compiles for arrays of the basic unitary types. If I have an array of structs, then I get a missing braces warning and the warning only goes away if I change {0} for {{0}}.

struct my_type my_thing[NUMBER_OF_THINGS] = {0};

becomes

struct my_type my_thing[NUMBER_OF_THINGS] = {{0}};

This does not work, however, for arrays of structs which have struct members. Then the problem is with the 4.4.2 compiler, which gives missing initialiser errors, so I had to do this:

struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};

This satisfies the compilers, but it trips our MISRA checker, because MISRA demands either the universal single {0} initialiser or the full, whole-array initialiser:

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}};

This is impractical for us because we have all sorts of restrictions and NUMBER_OF_THINGS may be changeable and be automatically generated from outside the source code at build time.

Nub and Crux

I would like to be able to say to my boss that the so-called universal initialiser {0} is sufficient for initialising any array. I have found threads on the GCC mailing lists and Bugzilla, going back many years, which consider the compiler warnings I've mentioned to be bugs, and stating that {0} is part of the standard. However, none of them mention which standard, and I have been unable to find {0} in the ISO C89 or C99 drafts, or K&R v2. Is the {0} a standard? Is there any way to guarantee that an array of structs with struct members is initialised to all zeros (or NULL)?

The trouble is that, while I can magic away the violations of the MISRA code, I am unsure that doing this:

struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};

...is sufficient to guarantee that the array will be completely zeroed.

Can anyone please offer wisdom from the root of this problem?


回答1:


The {0} initializer to initialize all objects in an aggregate (meaning array or struct) is 100% standard in any version of C. The syntax allows you to omit the braces for sub-aggregates.

I won't go into all the dirty details here. In case you are interested in the formal normative text, this is explained in a number of intricate rules that you can read about in for example C11 6.7.9 from §17 and forward.


Regarding MISRA-C:2004, this rule was a bit cumbersome and there is a MISRA-C:2004 TC1 regarding it. Your static analyser might not properly implement TC1 9.2 which stated that {0} on the top level is compliant.

Still, the TC1 didn't quite sort all things out. I asked the committee about this back in 2008 here:

https://www.misra.org.uk/forum/viewtopic.php?f=65&t=750

The reply I got there is a formal committee response and may be used as reference in your documentation. The committee agreed that the rule needed further improvement and based on this the rule was fixed in MISRA-C:2012 where {0} may be used anywhere to initialize subobjects of aggregate type.

I would recommend to use MISRA-C:2012 if possible.




回答2:


Yes. {0} is valid universal initializer in C89, too:

If there are fewer initializers in a list than there are members of an aggregate, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

It's true in all newer versions of the standard as well.

The warning you get from gcc is an old bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80454 which was fixed around gcc 4.9.

For your situation, you could consider:

  • upgrade to a newer gcc (3.2.3 is too old!)
  • Use -Wno-missing-braces option to silence the warning since this is a known bug
  • Use memset to initialize your struct types



回答3:


The "universal initializer" {0} should work. For C89, the relevant paragraphs of section 3.5.7 are:

Otherwise, the initializer for an object that has aggregate type shall be a brace-enclosed list of initializers for the members of the aggregate, written in increasing subscript or member order; and the initializer for an object that has union type shall be a brace-enclosed initializer for the first member of the union.

If the aggregate contains members that are aggregates or unions, or if the first member of a union is an aggregate or union, the rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the members of the subaggregate or the first member of the contained union. Otherwise, only enough initializers from the list are taken to account for the members of the first subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next member of the aggregate of which the current subaggregate or contained union is a part.

If there are fewer initializers in a list than there are members of an aggregate, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.



来源:https://stackoverflow.com/questions/63355760/how-standard-is-the-0-initializer-in-c89

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!