据我了解,调用assert(e)
,其中e
是一个布尔表达式,执行类似于if (!e) { printf("%s:%d: failed assertion `%s'n", __FILE__, __LINE__, e); abort(); }
的东西,如果给定的表达式不为真,则突然终止程序。
另一方面,与其使用assert
,我可能会写一些像if (!e) { fprintf(stderr, "custom error message.n"); exit(1); }
这样的东西,天真地感觉更干净,更好。
忽略可以使用NDEBUG
标志全局关闭assert
,您认为一个比另一个还有什么其他优势?我是否得到了正确的区分,或者两者之间是否存在我不知道的概念差异,让两种条件程序终止方式有自己的利基用例?如果是后者,请解释。谢谢。
assert
的最大优点是它清楚地表明了一个人的意图。 如果你看到assert(some_condition)
那么你就知道作者的意图是什么(即,some_condition
总是true
)。 使用您的内联版本,在我实际阅读您的if
块并意识到您将显示错误消息并终止程序之前,我无法假设意图。
不太重要的原因包括assert
减少复制/粘贴错误,some_condition
自动转换为字符串(包括保留变量名称),以及工具可以理解它。
你认为一个比另一个还有什么其他优势?
使用宏是因为您希望能够通过条件编译将其删除。换句话说,您甚至不希望代码出现在二进制文件中。
我是否得到了正确的区分,或者两者之间是否存在我不知道的概念差异,让两种条件程序终止方式有自己的利基用例?
好吧,即使您使用1
作为"不成功"的退出代码,exit()
和abort()
的行为方式也不相同。后者旨在立即终止程序而无需进一步的工作,并可能触发调试提示或保存进程空间的图像(尽管它的作用取决于提供它的供应商)。前者通过atexit()
调用注册函数。还有其他停止方式,请参阅quick_exit()
和_Exit()
。
对于C++,对行为差异有更多的考虑,例如,是否运行堆栈帧中变量的析构函数,是否运行全局析构函数,如果在执行此操作时抛出异常会发生什么,等等。
'assert' 是一个代码自动测试工具。有时,即使满足导致执行断言的条件,程序也不应在客户端(发布版本)停止其工作。 例如:
switch(color)
{
case red:
//...
break;
case green:
//...
break;
default:
assert(false && "unexpected color value. 'enum color' was modified?");
}
再比如:
if ( OkOrFailEnum::OK != result )
{
assert(false && "data access fail");
throw std::runtime_error("Can not get index " + std::to_string(index));
}
同时,"assert"是一个代码注释工具。
inline unsigned Sum(unsigned* pPos, unsigned* pOffset)
{
assert(nullptr != pPos); //
assert(nullptr != pOffset); // | preconditions
assert(*pPos + *pOffset < *pOffset && "Overflow?"); // /
return *pPos + *pOffset;
}
断言:
assert(*pPos + *pOffset < *pOffset && "Overflow?");
意味着,Sum(..) 函数不能在大和中正常工作,它必须在调用函数之前进行一些检查。