我想定义一个assert
宏,它与标准assert(3)
调用相同,只是在定义NDEBUG
时预处理器不会删除它。
这样的调用,让我们在这里称之为assert2
,例如,如果你想在软件的发行版本中进行一些检查,那么它是有用的。
我怎样才能以合理的便携方式做到这一点?我总是可以完全重新创建assert
机制,例如 1 :
#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
调用做了很好的事情,比如处理编译器和平台的所有各种奇怪的东西,用特殊的魔法注释断言条件,让编译器在调用后假设条件成立,漂亮的打印功能名字,等等。
在包含assert
之前,我可以仅通过#undef NDEBUG
获取内置assert.h
- 但我无法看到如何将其重命名为assert2
。我想我可以诉诸副本&将系统头文件中assert
的定义粘贴到#define assert2
行,但这是(a)可能违反某些许可或版权,(b)需要为每个平台重复。
请不要开始讨论这种功能是否有用,或者它是否是实现更高级别目标的合理方式。我具体询问是否可以在不依赖assert
的情况下以其他名称重复使用现有的NDEBUG
来电。
1 当然,将die_now
声明为static
函数并不理想,因为它会在每个编译单元中复制die_now
函数使用assert
(或者更糟糕的是,甚至可能只是包含标题的那些),所以它应该在自己的并发单元中进行实际定义,但这是使用的另一个复杂因素这个功能。
答案 0 :(得分:2)
我反过来这样做:永远不要定义NDEBUG
,因此始终启用assert
,并定义assert2
,这是一个无操作或assert
的别名。然后你可以随意打开和关闭assert2
:
// 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
现在,您可以在定义或取消定义"assert2.h"
后重新包括NDEBUG
来回来回切换。上面的文件总是取消定义NDEBUG作为副作用,但你可以在最后从NDEBUG2
复制它。