我正在整理一些旧代码,这些代码到处使用“幻数”来设置硬件寄存器,并且我想使用常量而不是这些数字来使代码更具表现力(事实上,它们将映射到名称/用于记录寄存器的值)。
然而,我担心随着变化量的增加,我可能会打破神奇的数字。 这是一个简化的示例(寄存器集更复杂):
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/非升压环境答案感兴趣,因为这是驱动程序/内核代码。
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;
so instead of :
set_register(5);
we have:
set_register(state1|mode1);
What I'm looking for is a build time version of:
ASSERT(5==(state1|mode1));
Update
@Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
发布评论
评论(11)
新答案:
在我原来的答案(如下)中,我必须有两个不同的宏来支持函数范围和全局范围内的断言。 我想知道是否有可能提出一个适用于这两个范围的单一解决方案。
我找到了一个适用于使用外部字符数组的 Visual Studio 和 Comeau 编译器的解决方案。 但我找到了一个适用于 GCC 的更复杂的解决方案。 但GCC的解决方案不适用于Visual Studio。 :( 但是添加“#ifdef __ GNUC __”,可以轻松为给定编译器选择正确的宏集。
解决方案:
以下是
STATIC_ASSERT(1= 报告的错误消息) =1, test_message);
在 test.c 的第 22 行:GCC:
Visual Studio:
Comeau:
原始答案:
我做的事情与跳棋非常相似。 但我包含一条将在许多编译器中显示的消息:
并且要在全局范围(函数之外)执行某些操作,请使用以下命令:
NEW ANSWER :
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.
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.
Solution:
Here are the error messages reported for
STATIC_ASSERT(1==1, test_message);
at line 22 of test.c:GCC:
Visual Studio:
Comeau:
ORIGINAL ANSWER :
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
And for doing something at the global scope (outside a function) use this:
有一篇文章由
Ralf Holly 检查 C 中静态断言的不同选项。
他提出了三种不同的方法:
负维度他的最佳实现的结论是:
There is an article by
Ralf Holly that examines different options for static asserts in C.
He presents three different approaches:
His conclusion for the best implementation is this:
查看 boost 的静态断言
Checkout boost's static assert
如果您无法访问第三方库静态断言函数(如 boost),您可以推出自己的静态断言:
当然,缺点是错误消息不会很有帮助,但至少,它会给你行号。
You can roll your own static assert if you don't have access to a third-party library static assert function (like boost):
The downside is, of course, that error message is not going to be very helpful, but at least, it will give you the line number.
它可以随时随地使用。
我认为这是最简单的解决方案。
使用之前,请使用编译器仔细测试它。
It can be used anywhere, any times.
I think it is the easiest solution.
Before usage, test it with your compiler carefully.
此处列出的任何技术都应该有效,并且当 C++0x 可用时,您将能够使用内置的
static_assert
关键字。Any of the techniques listed here should work and when C++0x becomes available you will be able to use the built-in
static_assert
keyword.如果您有 Boost,那么使用
BOOST_STATIC_ASSERT
是最佳选择。 如果您使用 C 或者不想获得 Boost这是我的
c_assert.h
文件,它定义(并解释了其工作原理)一些处理静态断言的宏。它应该更复杂一些,因为在 ANSI C 代码中,您需要 2 个不同的宏 - 一个可以在您有声明的区域中工作,另一个可以在普通语句所在的区域中工作。 还有一些工作需要让宏在全局范围或块范围内工作,以及一堆垃圾以确保不存在名称冲突。
STATIC_ASSERT()
可以在变量声明块或全局范围内使用。STATIC_ASSERT_EX()
可以属于常规语句。对于 C++ 代码(或允许声明与语句混合的 C99 代码),
STATIC_ASSERT()
将在任何地方工作。If you have Boost then using
BOOST_STATIC_ASSERT
is the way to go. If you're using C or don't want to get Boosthere's my
c_assert.h
file that defines (and explains the workings of) a few macros to handle static assertions.It's a bit more convoluted that it should be because in ANSI C code you need 2 different macros - one that can work in the area where you have declarations and one that can work in the area where normal statements go. There is a also a bit of work that goes into making the macro work at global scope or in block scope and a bunch of gunk to ensure that there are no name collisions.
STATIC_ASSERT()
can be used in the variable declaration block or global scope.STATIC_ASSERT_EX()
can be among regular statements.For C++ code (or C99 code that allow declarations mixed with statements)
STATIC_ASSERT()
will work anywhere.尝试:
然后你可以写:
这可能会给你一个更好的错误消息(取决于你的编译器)。
Try:
Then you can write:
Which may give you a better error message (depending on your compiler).
常见的、可移植的选项是,
但在这种情况下不起作用,因为它们是 C 常量,而不是
#define
。您可以查看 Linux 内核的
BUILD_BUG_ON
宏来处理您的情况:当
condition
为 true 时,这将变为((void)sizeof(char[-1] ))
,这是非法的,应该在编译时失败,否则它就变成((void)sizeof(char[1]))
,这样就可以了。The common, portable option is
but it doesn't work in this case, because they're C constants and not
#define
s.You can see the Linux kernel's
BUILD_BUG_ON
macro for something that handles your case:When
condition
is true, this becomes((void)sizeof(char[-1]))
, which is illegal and should fail at compile time, and otherwise it becomes((void)sizeof(char[1]))
, which is just fine.确保使用足够新的编译器进行编译(例如
gcc -std=c11
)。那么你的陈述很简单:
Ensure you compile with a sufficiently recent compiler (e.g.
gcc -std=c11
).Then your statement is simply:
这不像一行 MY_ASSERT(expr) 解决方案那么优雅。 您可以在编译 C 代码之前使用 sed、awk 或 m4 宏处理器来生成 MY_ASSERT(expr) 的 DEBUG 代码扩展为多行或 NODEBUG 代码,从而在生产中删除它们。
This is not as elegant as a one line MY_ASSERT(expr) solution. You could use sed, awk, or m4 macro processor before compiling your C code to generate the DEBUG code expansion of MY_ASSERT(expr) to multiple lines or NODEBUG code which removes them for production.