在编译时检查常量变量的值
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_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 选项进行编译。
初始化时指定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 中可能很好地列举了什么是常量表达式。数组下标[]
和成员访问.
运算符的结果不是常量表达式,因此不能用于静态断言
为了高效的代码维护,我需要确保数组索引 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 选项进行编译。
初始化时指定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 中可能很好地列举了什么是常量表达式。数组下标[]
和成员访问.
运算符的结果不是常量表达式,因此不能用于静态断言