问题描述
我想定义一个assert
宏,它与标准 assert(3)
调用,只是定义了NDEBUG
时预处理器不会将其删除.
I would like to define an assert
macro which is identical to the standard assert(3)
call except that it isn't removed by the pre-processor when NDEBUG
is defined.
例如,如果您还希望在软件的发行版本中进行一些检查,那么这样的调用(在这里我们称为assert2
)很有用.
Such a call, let us call it assert2
here, is useful for example if you want to have some checks happen in release versions of software as well.
我该如何以合理的便携式方式执行此操作?我总是可以完全重新创建assert
机制,例如:
How can I do this in a reasonably portable way? I could always just completely re-create the assert
mechanism, like:
#define assert2(cond) cond ? (void)0 : die_now(#cond, __FILE__, __LINE__)
static die_now(char *cond_str, const char *file, int line) {
// print a message to stderr here
...
abort(); // or maybe abort ?
}
...但是我更愿意使用与现有断言调用相同的机制.特别是,内置的assert
调用可以完成很多不错的工作,例如处理编译器和平台的所有各种怪异现象,并通过特殊的魔术符注释断言条件,从而使编译器假定该条件在调用后成立,并打印出漂亮的函数名称,等等.
... but I'd much rather just use the same mechanism as the existing assert call. In particular, the built-in assert
call does nice stuff like handling all the various weirdnesses of your compiler and platform, annotating the assert condition with special magic that lets the compiler assume the condition holds after the call, pretty printing function names, and so on.
在包含assert.h
之前,我可以通过#undef NDEBUG
获得内置的assert
-但我看不到如何将其重命名为assert2
.我想我可以求助于&将系统头文件中assert
的 definition 粘贴到#define assert2
行中,但这是(a)可能违反某些许可证或版权,并且(b)需要重复以下操作:每个平台.
I could get the builtin assert
by just #undef NDEBUG
before including assert.h
- but I can't see how to rename it to assert2
. I guess I could resort to copy & pasting the definition of assert
in the system header files into the #define assert2
line, but this is (a) a possible violation of some license or copyright and (b) would need to be repeated for each platform.
请不要争论这种功能是否有用,或者它是否是实现更高层次目标的合理方法.我专门问我是否可以在不依赖NDEBUG
的情况下以另一个名称重用现有的assert
调用.
Please don't start a debate whether such a function is useful or not, or whether it's a reasonable way to accomplish a higher-level aim. I am asking specifically whether I can re-use the existing assert
call, under another name, without the dependence on NDEBUG
.
当然,将die_now
声明为static
函数并不理想,因为它将在每个用作assert
的编译单元中复制die_now
函数(或更糟糕的是, ,甚至可能只包含标头的所有内容都可以),因此应确实在其自己的复杂单元中对它进行脱机定义,但这是使用此函数的另一复杂情况.
Of course, declaring die_now
as a static
function isn't ideal since it will duplicate the die_now
function in every compilation unit that uses as assert
(or worse, perhaps even all those that just include the header), so it should really be defined out-of-line in its own complication unit, but that's another complication to the use of this function.
推荐答案
我将采用另一种方法:永远不要定义NDEBUG
,因此始终启用assert
,并定义assert2
无操作或assert
的别名.然后,您可以根据需要打开和关闭assert2
:
I'd do this the other way around: never define NDEBUG
, so assert
is always enabled, and define an assert2
which is either a no-op or an alias of assert
. Then you can turn assert2
on and off at your pleasure:
// Note: no include guard
//
// Copy NDEBUG to NDEBUG2
#undef NDEBUG2
#ifdef NDEBUG
#define NDEBUG2 1
#endif
#undef NDEBUG
/* include <assert.h>, so that assert and friends are defined
* assert.h also lacks an include guard, but multiple inclusions
* are required to be OK (section 7.1.2 paragraph 4, if you care.)
*/
#include <assert.h>
/* Now define an assert which respects the original NDEBUG */
#undef assert2
#ifdef NDEBUG2
#define assert2(x)
#else
#define assert2 assert
#endif
现在,您可以在定义或取消定义NDEBUG
之后通过包含"assert2.h"
来回切换.上面的文件始终未将NDEBUG定义为副作用,但是您可以最后从NDEBUG2
复制回去.
Now you can flip back and forth by reincluding "assert2.h"
after defining or undefining NDEBUG
. The above file always undefines NDEBUG as a side-effect, but you could copy it back from NDEBUG2
at the end.
这篇关于定义一个有效的断言,即使定义了NDEBUG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!