【问题标题】:Avoiding null-initialized holes when using designated initializers使用指定的初始化器时避免空初始化的空洞
【发布时间】:2013-04-23 13:27:19
【问题描述】:

我有一个这样的枚举:

enum {
  ID_FOO = 0,
  ID_BAR,
  ID_BAZ
}

还有一个使用指定初始化器(如 hat)的常量数组:

char* arr[] = {
  [ID_FOO] = "foo stuff",
  [ID_BAR] = "bar stuff",
  [ID_BAZ] = "baz stuff",
  0
}

现在当我向枚举添加一个值时,例如在ID_FOO 之后但忘记将其添加到数组中,那么我会在数组中得到一个 uninitialized 空初始化的“洞”。有什么办法可以防止这种情况发生,或者至少得到编译器的警告?

非便携式 GCC-only 解决方案很好。

【问题讨论】:

  • 如果有任何初始化程序,没有显式初始化程序的元素将被初始化为(类型适当的值)零,因此没有未初始化的漏洞。但我猜你想在这里被警告默认的空指针?
  • @DanielFischer 是的,我不想要任何空指针。
  • @DanielFischer 你有这方面的参考吗?
  • @abergmeier 在 n1570 中是 6.7.9,第 19 条:“所有未显式初始化的子对象都应隐式初始化,与具有静态存储持续时间的对象相同。”

标签: c gcc


【解决方案1】:

一种方法是为您的枚举添加一个标记最大值,您可以使用它来验证该最大值是否与数组中的元素数相同。

enum {
    ID_FOO = 0,
    ID_BAR,
    ID_BAZ,
    // insert new values here

    ID_MAX
}

assert(ID_MAX == (sizeof(arr)/sizeof(arr[0]) - 1));

这是运行时检查;请查看C compiler asserts - how to implement?,了解如何获取编译时错误。

【讨论】:

  • 会有用的。但我真的不喜欢运行时断言,而静态断言在 C 中似乎很难看。
  • 是的。我要使用 GCC 4.6,因此我有 _Static_assert
【解决方案2】:

您可以使用X-Macros 使它们保持同步,尽管有些人可能会争论生成的代码是否漂亮。

我们的想法是获取两个结构所需的所有信息并将其放入一个宏中:

entries.inc

ENTRY(ID_FOO, "foo stuff")
ENTRY(ID_BAR, "bar stuff")
ENTRY(ID_BAZ, "baz stuff")

然后,重新定义您的宏,以便为您需要构建的每个结构,从数据中提取适当的部分:

foo.c

/* here define what entry should be for your enums */
#define ENTRY(id, name) id,

enum {
#include "entries.inc"
};

/* and then redefine for the char array and include again */
#undef  ENTRY
#define ENTRY(id, name) [id] = name,

char* arr[] = {
  #include "entries.inc"
  0
};


int main(int argc, char* argv[]) {
  /* whatever */
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-15
    • 2019-08-30
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    • 2018-02-17
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多