断言(0)是什么意思?

时间:2015-12-12 05:31:05

标签: c++ c assert assertion

我的一次考试中有这样的问题,而且我还不太清楚如何回答。我理解断言是测试程序的方法,但是我不太确定 assert(0) 正在检查什么。这是一个棘手的问题吗?它总会失败,但我不明白为什么。什么检查?

任何解释都会很棒,谢谢。

4 个答案:

答案 0 :(得分:30)

C ++标准将assert的定义推迟到C标准。

C99§7.2/ 2:
  

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>

C ++11§17.6.2.2/ 2:
  

翻译单元可以按任何顺序包含库标题(第2条)。每个可能包括更多   一次,除了包含NDEBUG<cassert>的效果每次都取决于<assert.h>的词汇当前定义之外,没有任何效果与被恰好包含一次有效。

上面讨论的双重打击的合理定义同样取决于NDEBUG没有包含保护,例如

文件 assert_should_never_get_here.hpp
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)并不完全像抛出一些异常(因为可以捕获异常)