我的一次考试中有这样的问题,而且我还不太清楚如何回答。我理解断言是测试程序的方法,但是我不太确定 assert(0)
正在检查什么。这是一个棘手的问题吗?它总会失败,但我不明白为什么。什么检查?
任何解释都会很棒,谢谢。
答案 0 :(得分:30)
C ++标准将assert
的定义推迟到C标准。
“
assert
宏将诊断测试放入程序中;它扩展为void表达式。执行时,如果表达式(应具有标量类型)为false(即,比较等于0),则断言宏会写入有关失败的特定调用的信息(包括文本参数,源文件的名称,源行号和封闭函数的名称 - 后者分别是预处理宏__FILE__
和__LINE__
以及标识符{{的值1}})在实现定义格式的标准错误文件上。然后它调用__func__
函数。
在abort
assert(0)
被解释为0
,因此当断言检查开启时,此断言将始终失败,或触发。
因此它断言
“执行永远不会达到这一点。”
在实践中,很难让编译器关闭执行到达或未达到给定点。通常,编译器会首先抱怨执行可能到达函数的末尾而不返回值。添加false
应该理想地解决这个问题,但是编译器可能会抱怨assert(0)
,或者没有认识到它说你已经很清楚它试图警告的内容。
然后,一个(1)可能的措施是在此时抛出异常:
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
之前定义符号NDEBUG
。
此标头具有特殊支持,因此您可以多次添加,无论是否定义<assert.h>
。
“翻译单元可以按任何顺序包含库标题(第2条)。每个可能包括更多 一次,除了包含
NDEBUG
或<cassert>
的效果每次都取决于<assert.h>
的词汇当前定义之外,没有任何效果与被恰好包含一次有效。
上面讨论的双重打击的合理定义同样取决于NDEBUG
没有包含保护,例如
NDEBUG
免责声明:虽然我在21世纪初对其进行了多次编码,但为了这个答案,我编写了上面的代码,虽然我用g ++测试它,但它可能不一定是完美的。
(1)有关另一种可能性的讨论,请参阅Basile Starynkevitch's answer,g ++特定的内在#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
。
功能
答案 1 :(得分:12)
永远都会失败。这就是它。它总是会失败的原因是,只要x = 5,“assert(x == 5)”就会成功。
如果您要求应用程序,那么您可以将其放在真正不应该发生的代码块中。
switch(suit) {
case CLUB:
case DIAMOND:
case HEART:
case SPADE:
// ...
default:
assert(0);
}
答案 2 :(得分:9)
是的,它总会失败。
assert(0)
或assert(false)
通常用于标记无法访问的代码,因此在调试模式下会发出诊断消息,并且当实际上无法访问时,程序将中止达到了,这是一个明确的信号,表明该计划没有按照我们的想法行事。
答案 3 :(得分:3)
在添加到其他答案(特别是this之一)中,如果您使用的是最近的GCC(或Clang),则可以考虑使用某些答案GCC builtin,特别是__builtin_unreachable()
而不是assert(0)
。
存在一些差异:首先,可以使用assert
禁用-DNDEBUG
。 __builtin_unreachable
将改变编译器优化代码的方式。
当然,有些编译器不了解__builtin_unreachable
。
你还可以考虑调用一些[[noreturn]]
C ++函数(在C ++ 11或更高版本中) - 或__attribute__((noreturn))
调用GCC,例如abort()
BTW,assert(0)
并不完全像抛出一些异常(因为可以捕获异常)