【发布时间】:2018-12-12 08:20:49
【问题描述】:
为了有效地维护代码,我需要确保数组索引 0 处的值是特定的预定义值。以下代码不起作用:
#define SPECIFIC_ADDR_IDX 0
#define SPECIFIC_ADDR 8
#define NOT_SPECIFIC_ADDR1 12
#define NOT_SPECIFIC_ADDR2 16
typedef struct _struct_s
{
const uint16_t addr; // addresses are constant and are not mutable
uint32_t val;
} struct_s;
struct_s globArr[] =
{
{.addr = SPECIFIC_ADDR, .val = 0},
{.addr = NOT_SPECIFIC_ADDR1, .val = 0},
{.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};
// make sure the address at the SPECIFIC_ADDR_IDX is SPECIFIC_ADDR
_Static_assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, " Illegal!");
它给出以下编译错误:
error: expression in static assertion is not constant
_Static_assert (globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, " Illegal!");
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
addr 被定义为const uint16_t,所以我认为它的值在编译时是已知的。
有没有一种在编译时执行这种检查的有效方法?
澄清:我知道这样我不能使用_Static_assert,const 不会在编译时知道变量的值。我要问的是是否有人知道处理此类问题的任何技巧。
令人满意的解决方案由 Kamil Cuk 提出。初始化可以通过指定索引来完成:
struct_t globArr[] =
{
[SPECIFIC_ADDR_IDX] = { .addr = SPECIFIC_ADDR, .val = 0 },
{.addr = NOT_SPECIFIC_ADDR1, .val = 0},
{.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};
在这种情况下,如果在索引 [SPECIFIC_ADDR_IDX] 处有额外的条目初始化,编译器将发出警告(不保证,但大多数编译器会)。只需确保在 warning=error 选项打开的情况下进行编译。
【问题讨论】:
-
globArr不是常量表达式。变量值不是常量表达式。 -
为什么不在运行时(在调试版本中)?当它是默认值时,为什么你需要用零初始化?
-
您的 static_assert 将检查您的第一个初始化行是否将
SPECIFIC_ADDR添加到成员.addr。您的代码在检查分配的正确值上方有 6 行。你想断言什么?如果有人更改了初始化列表,她也可以更改静态断言。 -
@i486 这只是一个例子。你可以用 0 忽略初始化。
-
@harper 对。但是,如果有人向
globArr添加条目,然后编译失败,这将表明添加静态断言不是为了好玩,而是有一个原因,并且可能最合乎逻辑的方法是挖掘并理解它的原因已添加或仅将 SPECIFIC_ADDR 保留为 SPECIFIC_ADDR_IDX。另请注意,这只是一个示例。在实际项目中,数组要大得多,而不仅仅是您在此处看到的 6 行。
标签: c constants static-assert