C89中{0}初始化程序的标准如何? 小结和症结

问题描述

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

我们使用脚踏开关和c89标准以及大量其他限制运行构建检查。限制之一是必须在声明时初始化所有数据。

我有一个问题,在GCC 3.2.3上,通用零初始化程序{0}仅针对基本单一类型的数组进行编译。如果我有一个结构数组,那么我会得到一个缺失的大括号警告,并且仅当我将{0}更改为{{0}}时,警告才会消失。

struct my_type my_thing[NUMBER_OF_THINGS] = {0};

成为

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

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

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

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

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

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

小结和症结

我想对老板说,所谓的通用初始化器{0}足以初始化任何数组。我在GCC邮件列表和Bugzilla上发现了线程,这些线程可以追溯到很多年前,它们考虑了我提到的编译器警告是bug,并指出{0}是标准的一部分。但是,他们都没有提到哪个标准,而且在ISO C89或C99草案或K&R v2中我找不到{0} {0}是一个标准吗? 有什么方法可以保证将带有struct成员的struct数组初始化为全零(或NULL)?

问题在于,尽管我可以消除对MISRA代码的违反,但我不确定这样做:

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

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

有人能从这个问题的根源提供智慧吗?

解决方法

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

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


关于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。

,

是的。 {0}也是valid universal initializer in C89

如果列表中的初始化程序少于聚合成员,则聚合的其余部分应与具有静态存储期限的对象隐式初始化。

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

您从gcc收到的警告是一个古老的错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80454 固定在gcc 4.9左右。

根据您的情况,您可以考虑:

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

“通用初始值设定项” {0}应该起作用。对于C89,第3.5.7节的相关段落如下:

否则,具有聚合类型的对象的初始值设定项应是用大括号括起来的聚合成员的初始值设定项列表,并以递增的下标或成员顺序编写;对于具有联合类型的对象,其初始值设定项应为联合的第一个成员的括号括起来的初始值设定项。

如果集合包含作为集合或联合的成员,或者如果联盟的第一个成员是集合或联合,则规则将递归应用于子集合或包含的联合。如果子集合或所包含的并集的初始化程序以左括号开头,则该括号括起来的初始化程序及其匹配的右括号会初始化子集合的成员或所包含的并集的第一个成员。否则,仅使用列表中足够的初始化程序来考虑第一个子聚合的成员或所包含的并集的第一个成员;剩下的所有初始化程序都将初始化当前子聚合或所包含的并集所属的聚合的下一个成员。

如果列表中的初始化程序少于聚合成员,则聚合的其余部分应与具有静态存储期限的对象隐式初始化。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...