在 C 中构建时断言表达式的方法 [英] Ways to ASSERT expressions at build time in C
问题描述
我正在整理一些旧代码,这些代码到处使用幻数"来设置硬件寄存器,我想使用常量而不是这些数字来使代码更具表现力(实际上它们会映射用于记录寄存器的名称/值).
I'm tidying up some older code that uses 'magic numbers' all over the place to set hardware registers, and I would like to use constants instead of these numbers to make the code somewhat more expressive (in fact they will map to the names/values used to document the registers).
但是,我担心随着更改量的增加,我可能会打破魔幻数字.下面是一个简化的例子(寄存器组更复杂):
However, I'm concerned that with the volume of changes I might break the magic numbers. Here is a simplified example (the register set is more complex):
const short mode0 = 0;
const short mode1 = 1;
const short mode2 = 2;
const short state0 = 0;
const short state1 = 4;
const short state2 = 8;
所以而不是:
set_register(5);
我们有:
set_register(state1|mode1);
我正在寻找的是构建时间版本:
ASSERT(5==(state1|mode1));
更新
@Christian,感谢您的快速回复,我对 C/非增强环境的回答也很感兴趣,因为这是驱动程序/内核代码.
@Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
推荐答案
新答案:
在我的原始答案(如下)中,我必须有两个不同的宏来支持函数作用域和全局作用域中的断言.我想知道是否有可能想出一个在两个范围内都适用的解决方案.
In my original answer (below), I had to have two different macros to support assertions in a function scope and at the global scope. I wondered if it was possible to come up with a single solution that would work in both scopes.
我找到了一个适用于使用外部字符数组的 Visual Studio 和 Comeau 编译器的解决方案.但是我能够找到适用于 GCC 的更复杂的解决方案.但是 GCC 的解决方案不适用于 Visual Studio.:( 但是添加'#ifdef __ GUC __',很容易为给定的编译器选择正确的宏集.
I was able to find a solution that worked for Visual Studio and Comeau compilers using extern character arrays. But I was able to find a more complex solution that works for GCC. But GCC's solution doesn't work for Visual Studio. :( But adding a '#ifdef __ GNUC __', it's easy to choose the right set of macros for a given compiler.
解决方案:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg)
(!!sizeof (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg)
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg)
extern char STATIC_ASSERTION__##msg[1];
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
以下是为 STATIC_ASSERT(1==1, test_message);
报告的错误消息,位于 test.c 的第 22 行:
Here are the error messages reported for STATIC_ASSERT(1==1, test_message);
at line 22 of test.c:
海湾合作委员会:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
Visual Studio:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
Comeau:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
原始答案:
我做的事情与 Checkers 所做的非常相似.但我添加了一条消息,该消息将出现在许多编译器中:
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
#define STATIC_ASSERT(expr, msg)
{
char STATIC_ASSERTION__##msg[(expr)?1:-1];
(void)STATIC_ASSERTION__##msg[0];
}
为了在全局范围内(在函数之外)做一些事情,使用这个:
And for doing something at the global scope (outside a function) use this:
#define GLOBAL_STATIC_ASSERT(expr, msg)
extern char STATIC_ASSERTION__##msg[1];
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
这篇关于在 C 中构建时断言表达式的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!