C89 中的 {0} 初始值设定项的标准如何?

Wal*_*ard 25 c gcc initialization misra c89

在我当前使用 MISRA 2004 标准的项目中,我们使用三个 GCC 编译器,版本 3.2.3、4.4.2 和 5.4.0。

我们使用 pedantic switch 和 c89 标准以及其他一些限制来运行构建检查。限制之一是所有数据必须在声明时初始化。

我有一个问题,在 GCC 3.2.3 上,通用零初始值设定项{0}只编译基本单一类型的数组。如果我有一个结构数组,那么我会收到一个缺少大括号的警告,并且只有当我更改{0}{{0}}.

struct my_type my_thing[NUMBER_OF_THINGS] = {0};
Run Code Online (Sandbox Code Playgroud)

变成

struct my_type my_thing[NUMBER_OF_THINGS] = {{0}};
Run Code Online (Sandbox Code Playgroud)

但是,这对于具有结构成员的结构数组不起作用。然后问题出在 4.4.2 编译器上,它会导致缺少初始化程序错误,所以我必须这样做:

struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};
Run Code Online (Sandbox Code Playgroud)

这满足编译器的要求,但它会触发我们的 MISRA 检查器,因为 MISRA 需要通用单个 {0} 初始化程序或完整的全数组初始化程序:

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}};
Run Code Online (Sandbox Code Playgroud)

这对我们来说是不切实际的,因为我们有各种各样的限制,并且NUMBER_OF_THINGS可能是可变的,并且在构建时从源代码外部自动生成。

小结和关键

我想对我的老板说,所谓的通用初始化{0}器足以初始化任何数组。我在 GCC 邮件列表和 Bugzilla 上发现了很多年前的线程,它们认为我提到的编译器警告是错误,并说明这{0}是标准的一部分。但是,他们都没有提到哪个标准,而且我{0}在 ISO C89 或 C99 草案或 K&R v2 中找不到。{0}一个标准呢?是否有什么办法能保证结构与结构成员的数组初始化为全零(或NULL)?

问题是,虽然我可以消除违反 MISRA 代码的情况,但我不确定这样做:

struct my_struct_with_structs_inside my_other_thing[NUMBER_OF_THINGS] = {{0, 0, {0}, 0}};
Run Code Online (Sandbox Code Playgroud)

...足以保证数组将完全归零。

任何人都可以从这个问题的根源提供智慧吗?

Lun*_*din 24

在任何版本的 C 中,{0}用于初始化聚合(即数组或结构)中所有对象的初始化程序都是100% 标准的。语法允许您省略子聚合的大括号。

我不会在这里讨论所有肮脏的细节。如果您对正式的规范性文本感兴趣,可以在许多复杂的规则中对此进行解释,例如 C11 6.7.9 §17 及以后的内容。


关于 MISRA-C:2004,这条规则有点繁琐,有一个 MISRA-C:2004 TC1 关于它。您的静态分析器可能无法正确实施 TC1 9.2,该标准表明{0}顶层是合规的。

尽管如此,TC1 并没有完全解决所有问题。我早在 2008 年就在这里向委员会询问过这个问题:

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

我在那里得到的答复是委员会的正式答复,可以在您的文档中用作参考。委员会同意该规则需要进一步改进,并基于此规则在 MISRA-C:2012 中得到修复,{0}可以在任何地方用于初始化聚合类型的子对象。

如果可能,我建议使用 MISRA-C:2012。


P.P*_*.P. 7

是的。在 C89 中{0}也是有效的通用初始值设定项

如果列表中的初始值设定项少于聚合的成员数,则聚合的其余部分应与具有静态存储持续时间的对象隐式初始化相同。

在所有较新版本的标准中也是如此。

您从 gcc 收到的警告是一个旧错误:https : //gcc.gnu.org/bugzilla/show_bug.cgi?id=80454 ,已在 gcc 4.9 附近修复。

针对你的情况,你可以考虑:

  • 升级到更新的 gcc(3.2.3 太旧了!)
  • 使用-Wno-missing-braces选项使警告静音,因为这是一个已知错误
  • 使用memset初始化您的结构类型

  • 根据 MISRA 规则工作的人员正在开发安全关键型软件。“极不可能”不是一个可接受的正确性标准,并且会导致人员死亡。 (8认同)
  • @EricPostpischil 没有人说这是一个可以接受的标准。建议将其作为 OP 的“这种”情况的“潜在选项之一”。我还链接了相关信息,由 OP 和其他人决定是否适合他们。此外,答案不仅仅针对OP - 其他正在编写非MISRA环境的人也可能有相同/类似的问题。但请随意对我提出刑事指控。 (3认同)
  • @user694733 或浮点成员。无法保证全零位模式表示零浮点值。 (3认同)
  • 对于代码在某些奇异系统上运行的不太可能发生的情况发出警告:如果系统使用非零位模式 NULL 指针,则“memset”将无法正确初始化带有指针成员的结构。 (2认同)