C 枚举和标识符列表不'时导致编译器错误;长度不相称
我们的系统中有一个枚举,如下所示:C 枚举和标识符列表不'时导致编译器错误;长度不相称,c,C,我们的系统中有一个枚举,如下所示: enum EventCode { BAD_CONFIG = 0, BAD_NET = 1, ... BAD_UNKNOWN = 92, // This should always be at the end, and the numbers in // this list should be continuous! EVENT_LIST_LENGTH } 以及相应的事件模式标识符列表: int even
enum EventCode {
BAD_CONFIG = 0,
BAD_NET = 1,
...
BAD_UNKNOWN = 92,
// This should always be at the end, and the numbers in
// this list should be continuous!
EVENT_LIST_LENGTH
}
以及相应的事件模式标识符列表:
int eventModeType[] = {
INT32,
...
INT16 // List position 92.
}
在某一点上增加了这一点:
enum EventCode {
...
BAD_UNKNOWN = 92,
NEW_ERROR = 100,
// This should always be at the end, and the numbers in
// this list should be continuous!
EVENT_LIST_LENGTH
}
即使在eventModeType
中添加了相应的模式,这一行显然导致了未定义的行为:
//哦,不,事件列表太长了!!!
for(无符号整数i=0;i
当
事件列表长度和事件模式类型的长度不匹配,因此没有人会犯此错误时,如何导致编译器错误?
我发现的一个解决方案是:
// macro to stop warning from unused variable.
#define _unused(x) ((void)x)
// Actual size of list.
const int EVENT_MODE_LIST_LENGTH = sizeof(eventModeType) / sizeof(eventModeType[0]);
// With -Werror turned on, the following function will produce the error:
// error : size of array 'arr' is too large
// in the event that EVENT_LIST_LENGTH is larger then EVENT_MODE_LIST_LENGTH
void evantModeArraySizeChecker(void)
{
int arr[EVENT_LIST_LENGTH - EVENT_MODE_LIST_LENGTH + 1];
_unused(arr);
int arr2[EVENT_MODE_LIST_LENGTH - EVENT_LIST_LENGTH + 1];
_unused(arr2);
}
如果此列表修改不正确,将导致编译器错误 您的问题只是
evenModeType
数组长度的计算错误。现代C为您提供了一个工具,它甚至可以避免像事件列表\u长度
这样的技巧。只需使用指定的初始化器:
int eventModeType[] = {
[BAD_CONFIG] = INT32,
...
[BAD_UNKNOWN] = INT16, // List position 92.
[NEW_ERROR] = WnatEver,
}
否则,如果您只想在枚举内的注释中禁止out,它会说:“这应该总是在末尾,并且此列表中的数字应该是连续的!”,那么您为什么要设置枚举中的所有值呢?如果只添加
NEW\u ERROR,
只需添加相应的模式,并最终使用sizeof进行检查。@Bob\u我刚才添加的注释就是为了警告人们这一点。这样做还有其他原因,例如,此列表表示同样存储在客户端用于反序列化这些事件的类似列表的事件。有了明确的数字,就更容易看到什么与什么相关。现代C有static\u assert
,让我们检查编译时是否满足了条件。不再需要导致不理解的编译器错误的奇怪数组表达式。@JensGustedt我想你指的是JensGustedt,是的,那太棒了,不幸的是我们的编译器不支持C11
。您应该将其添加为答案,我会对其进行投票。因此,在事件代码中出现“间隙”的情况下,相应的元素设置为0。在遍历数组之前如何检查?为什么要检查?这将仅打印问题示例中的0
。不管怎样,使用这种约定的代码应该编写为在这种情况下是健壮的,特别是知道如何处理特殊值0
@JensGustedt是的,你是对的,但问题是如果我们出于某种原因要求列表是连续的,并且没有0(在这种情况下,我们不需要这样做)那么我认为这个解决方案行不通。
int eventModeType[] = {
[BAD_CONFIG] = INT32,
...
[BAD_UNKNOWN] = INT16, // List position 92.
[NEW_ERROR] = WnatEver,
}