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

时间:2018-12-12 08:20:49

标签: c const static-assert

为了高效的代码维护,我需要确保数组索引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 选项为ON的情况下进行编译即可。

1 个答案:

答案 0 :(得分:1)

您只需在初始化中指定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中很好地枚举。数组下标[]和成员访问权.运算符的结果不是常量表达式,因此不能在静态断言中使用。