请解释一下,谢谢。
C++标准将assert
的定义推迟到C标准。
”
assert
宏将诊断测试放入程序中。它扩展为一个void表达式。当执行时,如果expression(必须具有标量类型)为false(即等于0),assert宏会以实现定义的格式将有关失败调用的特定信息(包括参数的文本、源文件的名称、源行号和封闭函数的名称-后者分别是预处理宏__FILE__和__LINE__和标识符__func__的值)写入标准错误文件。然后调用abort函数。
在assert(0)
中,0
被解释为false
,因此当启用断言检查时,此断言将始终失败或触发。
因此,它断言:
“执行永远不会到达此点。”
在实践中,使编译器停止关注执行是否到达给定点可能很困难。通常,编译器将首先抱怨函数可能到达末尾而不返回值。在那里添加一个assert(0)
应该理想地解决了这个问题,但是编译器可能会抱怨assert
,或者不认识它并尝试发出警告。
因此,一种可能的措施是在那一点上还抛出一个异常:
auto foo( int x )
-> int
{
if( x == 1 ) { return 42; }
assert( 0 ); throw 0; // Should never get here!
}
当然,这个双重打击可以被定义为一个更高级别的宏。关于异常类型,您可能希望将其保留为非std::exception
,因为这不是一个普通的catch
任何地方都可以捕获的异常。或者,如果您信任标准异常层次结构(我觉得这没有意义,但)您可以使用std::logic_error
。
要关闭assert
断言检查,您可以在包括<assert.h>
之前定义符号NDEBUG
。
此头文件具有特殊支持,以便您可以多次包含它,带或不带已定义的NDEBUG
。
”翻译单元可以按任何顺序包括库头文件(第2条)。每个头文件可以包含多次,与仅包含一次没有区别,除了每次包含
<cassert>
或<assert.h>
的影响取决于当前词汇定义的NDEBUG
。
上述讨论的合理定义类似地取决于NDEBUG
而没有包含保护,例如:
#include <stdexcept> // std::logic_error
#include <assert.h>
#undef ASSERT_SHOULD_NEVER_GET_HERE
#ifdef NDEBUG
# define ASSERT_SHOULD_NEVER_GET_HERE() \
throw std::logic_error( "Reached a supposed unreachable point" )
#else
# define ASSERT_SHOULD_NEVER_GET_HERE() \
do{ \
assert( "Reached a supposed unreachable point" && 0 ); \
throw 0; \
} while( 0 )
#endif
免责声明:虽然我在2000年代早期已经编写过类似的代码,但我为了这个答案而编写了上面的代码,并且尽管我使用g++测试过它,但它可能并不完美。
(1)参见Basile Starynkevitch 的答案,讨论另一种可能性——适用于 g++ 的内置函数 __builtin_unreachable
。
它会一直失败。基本上就是这样。它失败的原因和“assert(x==5)”在x等于5时成功的原因一样。
如果你问的是一个应用程序,那么你应该将其放在代码块中,这种情况确实不应该发生。
switch(suit) {
case CLUB:
case DIAMOND:
case HEART:
case SPADE:
// ...
default:
assert(0);
}
是的,它总会失败。
assert(0)
或 assert(false)
通常用于标记无法到达的代码,因此在调试模式下发出诊断消息并在实际到达无法到达的位置时中止程序,这是程序没有按照我们认为的方式运行的明确信号。
__builtin_unreachable()
,而不是assert(0)
。
有一些区别:首先,assert
可以使用-DNDEBUG
禁用。而__builtin_unreachable
将改变编译器优化代码的方式。
当然,有些编译器不知道__builtin_unreachable
。
您还可以考虑调用一些C++11或更高版本中的 [[noreturn]]
C++函数 - 或对于GCC,可以使用__attribute__((noreturn))
,例如abort()
。
顺便说一句,assert(0)
并不完全像抛出异常(因为异常可以被捕获)。
abort
。abort
的操作是否可以被拦截是一个实现细节。 - Cheers and hth. - Alfassert
(或abort
)时,在引发信号之前会将信号处理器重置为默认行为。 - Basile Starynkevitchabort
确实标记为[[noreturn]]
。所有这些都可以在man页面中找到。@Cheersandhth.-Alf:此行为似乎甚至是明确定义的。 - edmz
assert(“Blah”&&condition)
,而我支持assert((“Blah”,condition))
(我们两个都不喜欢感叹号)。现在我用&&
,因为它更简单、更易懂。但这就是为什么我之后支持(())
的原因... - Cheers and hth. - Alf