定义一个即使定义了NDEBUG也有效的断言

时间:2017-02-07 15:31:45

标签: c c-preprocessor assert

我想定义一个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(或者更糟糕的是,甚至可能只是包含标题的那些),所以它应该在自己的并发单元中进行实际定义,但这是使用的另一个复杂因素这个功能。

1 个答案:

答案 0 :(得分:2)

我反过来这样做:永远不要定义NDEBUG,因此始终启用assert,并定义assert2,这是一个无操作或assert的别名。然后你可以随意打开和关闭assert2

文件assert2.h

// 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复制它。