在编译时检查常量变量的值

Checking constant variable's value at the compilation time

为了高效的代码维护,我需要确保数组索引 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_assertconst不会使变量的值在编译时间。我想问的是,是否有人知道任何一种 技巧 来处理此类问题。

令人满意的解决方案 是由 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 选项进行编译。

初始化时指定intex即可:

#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_t;

struct_t globArr[] =
{
    [SPECIFIC_ADDR_IDX] = { .addr = SPECIFIC_ADDR, .val = 0 },
    {.addr = NOT_SPECIFIC_ADDR1, .val = 0},
    {.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};

无论如何你需要做运行时断言,所以使用断言:

void globArr_unittest(void) {
     assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR);
}

static_assert 需要常量表达式。您不能对变量值编写静态断言。即使你做了 static const struct_t globArr[] 仍然 globArr 值不是常量表达式。 C语言没有像C++那样的constexpr(或consteval)说明符。所以,遗憾的是,你不能在 C 中做到这一点。

const只是修饰符,表示不能通过这个句柄修改变量。 const 变量在 C 中可以被修改并且不是不可变的。

就像你做不到一样:

#if globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR

同样你不能

static_assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, "");

cppreference 中可能很好地列举了什么是常量表达式。数组下标[]和成员访问.运算符的结果不是常量表达式,因此不能用于静态断言