C99指定的初始化程序重复索引在构建输出或lint中根本没有标记

前几天我在指定的初始化程序中玩了一下,我惊讶地发现,多次使用相同的索引是有效的。 更重要的是,当我这样做时,它甚至没有产生编译器警告,错误甚至信息声明,甚至PC-Lint似乎也不关心(我认为最让我感到惊讶)。

我想知道编译器是否有理由在这种情况下甚至没有提供信息消息,或者是否有其他编译器/ lint /等。 可用于捕获或标记此选项的选项。

使用的工具:Renesas RX标准工具链v1.2.0.0(C99),gcc版本4.4.3(Ubuntu 4.4.3-4ubuntu5.1)(在VM中),Lint-NT 9.00i


例如,我正在处理的一些旧代码#defines一堆命令,然后创建一个命令结构数组(这里大大简化),循环查找并使用该特定命令:

#define CMD_RMEM 0 #define CMD_WMEM 1 #define CMD_XCRC 2 #define CMD_NULL 3 typedef struct { const char cmdID; const char* cmdStr; } CMD; const CMD commands[] = { {CMD_RMEM,"RMEM"}, {CMD_WMEM,"WMEM"}, {CMD_XCRC,"XCRC"}, {CMD_NULL,"NULL"}, }; 

然后我想起了我在某处看到的指定初始化语法,并认为除了检测重复的命令索引之外,它还可以为数组中项目的排列提供更大的灵活性,例如:

 //(same #def's & typedef as above) const CMD commands[] = { [CMD_RMEM] = {CMD_RMEM,"RMEM"}, [CMD_NULL] = {CMD_NULL,"NULL"}, //different order in ititializer list, // but designation keeps it in the same array/memory position, so // this will still be the 'last' element [CMD_CMEM] = {CMD_CMEM,"CMEM"}, [CMD_WMEM] = {CMD_WMEM,"WMEM"}, [CMD_XCRC] = {CMD_XCRC,"XCRC"}, }; 

会产生与上面的初始代码相同的效果,但可以灵活地安排数组声明中的项目(它确实如此)和(我在想/希望)

 #define CMD_RMEM 0 #define CMD_WMEM 1 #define CMD_XCRC 1 // obvious dupe in a short list, but not so obvious // if part of a much longer list or if split among multiple files #define CMD_NULL 2 // (Same designated initializer section as above) 

会产生至少一个警告,因为我们多次使用相同的指定索引(它没有 )(这个例子可能很容易通过添加命令而不移动最后一个NULL占位符)。


GCC Designated Inits页面注释了一个GNU扩展,它允许你在初始化器中使用范围,我可以看到它有用于定义整个范围然后覆盖某些部分(例如int arr[] = {[0 ... 99] = -1, [42] = 1} ,但我不明白为什么它仍然没有至少在某种程度上被标记……

在同一个GCC页面中,它确实解决了多个字段的主题,但没有解释它的行为原因:“如果同一字段多次初始化,则它具有上次初始化时的值。如果有的话这种被覆盖的初始化有副作用,未指明副作用是否发生。目前,GCC丢弃它们并发出警告。“

这个IBM页面也显示了一个有趣的例子,但仍然没有回答(至少对我来说)为什么它至少不是某种构建消息……

最后,从2000年12月开始的这个gcc补丁页面表明重复的检查被明确删除了 ,但没有(从我简要阅读的内容)解释了原因。

那么,为什么(貌似)掩饰了? 有没有办法让编译器(甚至lint)标记这个(提供更多的安全性)(在c / c99中;不要只说’使用c ++’或者某些东西:p)?

我没有解释为什么 – 或许只是因为指定的初始化器仍然是新的和很少使用。 编译器制造商必须考虑将受益于新function的程序员数量。

Clang警告你的构造:

 $ clang -std=c99 -Wall -c tc tc:24:17: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides] [CMD_XCRC] = {CMD_XCRC,"XCRC"}, ^~~~~~~~ tc:4:18: note: expanded from macro 'CMD_XCRC' #define CMD_XCRC 1 // obvious dupe in a short list, but not so obvious ^ tc:23:17: note: previous initialization is here [CMD_WMEM] = {CMD_WMEM,"WMEM"}, ^~~~~~~~ tc:2:18: note: expanded from macro 'CMD_WMEM' #define CMD_WMEM 1 ^ 

(我不得不对它进行微小的修改才能编译,但你明白了。)

 $ clang -v Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) Target: x86_64-apple-darwin12.3.0 Thread model: posix 

该标准预见到可能存在重复并强加解决此问题的策略,最后一个初始化程序获胜。 因此,对标准明确validation的代码的警告只会令人讨厌。 (例如某些编译器为“零”初始值设定项{0}提供的警告)

如果你的问题更多的是关于动机,我猜这些枚举是主要原因。 枚举具有重复值的情况并不少见,因此使用这些值初始化数组会引起严重的问题。

其他动机可能更多涉及。 看一下

 bool const usedSizes[] = { [sizeof(int)] = true, [sizeof(long)] = true, [sizeof(long long)] = true }; 

这里可以轻松复制初始化程序,但具体值与平台高度相关。