我的一次考试中有这样的问题,我仍然不太清楚如何回答这个问题.我知道断言是测试你的程序的方法,但是我不太清楚什么assert(0)
是检查.这是一个棘手的问题吗?它总会失败,但我不明白为什么.什么检查?
任何解释都会很棒,谢谢.
C++标准将定义推迟assert
到C标准.
"在
assert
宏观使诊断测试进入程序; 它扩展为void表达式.当它被执行时,如果表达式(它应具有标量类型)为假(即,比较等于0),则断言宏写入有关失败的特定调用的信息(包括参数的文本,名称源文件,源行号和封闭函数的名称 - 后者分别是实现定义格式的标准错误文件上的预处理宏__FILE__
和__LINE__
标识符的值__func__
.然后它调用该abort
函数.
在assert(0)
将0
被解释为false
,所以这种说法总是会失败,或火,当断言检查上.
因此它断言
"执行永远不会达到这一点."
在实践中,可能很难使编译器关闭执行到达或未到达给定点.通常,编译器会首先抱怨执行可能到达函数的末尾而不返回值.添加一个assert(0)
应该理想地解决这个问题,但是编译器可能会抱怨assert
,或者不认识到它说你已经很清楚它试图警告的内容.
然后,一(1)种可能的措施是在此时抛出异常:
auto foo( int x ) -> int { if( x == 1 ) { return 42; } assert( 0 ); throw 0; // Should never get here! }
当然,双重打击可以定义为更高级别的宏.关于异常类型,您可能希望将其保留为a std::exception
,因为这不是一个普通的catch
任何地方都可以捕获的异常.或者,如果您信任标准异常层次结构(对我来说没有意义,但是),您可以使用std::logic_error
.
要关闭assert
断言检查,您可以NDEBUG
在包含之前定义符号
.
此标头具有特殊支持,因此您可以多次包含它,无论是否NDEBUG
定义.
"翻译单位可以包括任何顺序的图书馆标题(第2条).每个可以被包括不止一次,除了每次包括
或
依赖于词汇当前定义的效果之外,没有任何效果与被恰好包括一次有效
NDEBUG
.
上面讨论的双重打击的合理定义同样可以取决于NDEBUG
没有包括防护,例如
#include// std::logic_error #include #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
免责声明:虽然我在21世纪初对其进行了多次编码,但为了这个答案,我编写了上面的代码,虽然我用g ++测试它,但它可能不一定是完美的.
(1)参见Basile Starynkevitch关于另一种可能性的讨论的答案,即g ++特定的内在函数__builtin_unreachable
.
它总是会失败.这就是它.它总是会失败的原因是,只要x = 5,"assert(x == 5)"就会成功.
如果你要求一个应用程序,那么你会把它放在真正不应该发生的代码块中.
switch(suit) { case CLUB: case DIAMOND: case HEART: case SPADE: // ... default: assert(0); }
是的,它总会失败.
assert(0)
或者assert(false)
通常用于标记无法访问的代码,以便在调试模式下发出诊断消息,并在实际到达所谓的无法访问时中止程序,这清楚地表明程序没有按照我们的想法行事.