前几天我玩了一下指定的初始化程序,令我惊讶的是,多次使用同一个索引是有效的。更重要的是,当我这样做时,它甚至没有产生编译器警告、错误甚至信息性声明,甚至 PC-Lint 似乎也不在乎(我认为这最让我感到惊讶)。
我想知道在这种情况下编译器是否有原因甚至不提供信息消息,或者是否有额外的编译器/lint/等。可用于捕获或标记此问题的选项。
使用的工具:Renesas RX Standard Toolchain 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)?