断言(0)是什么意思?

Smi*_*ern 26 c c++ assert assertion

我的一次考试中有这样的问题,我仍然不太清楚如何回答这个问题.我知道断言是测试你的程序的方法,但是我不太清楚什么assert(0)是检查.这是一个棘手的问题吗?它总会失败,但我不明白为什么.什么检查?

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

Che*_*Alf 30

C++标准将定义推迟assert到C标准.

C99§7.2/ 2:

"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!
}
Run Code Online (Sandbox Code Playgroud)

当然,双重打击可以定义为更高级别的宏.关于异常类型,您可能希望将其保留为a std::exception,因为这不是一个普通的catch任何地方都可以捕获的异常.或者,如果您信任标准异常层次结构(对我来说没有意义,但是),您可以使用std::logic_error.


要关闭assert断言检查,您可以NDEBUG在包含之前定义符号<assert.h>.

此标头具有特殊支持,因此您可以多次包含它,无论是否NDEBUG定义.

C++11§17.6.2.2/ 2:

"翻译单位可以包括任何顺序的图书馆标题(第2条).每个可以被包括不止一次,除了每次包括<cassert><assert.h>依赖于词汇当前定义的效果之外,没有任何效果与被恰好包括一次有效NDEBUG.

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

文件assert_should_never_get_here.hpp
#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
Run Code Online (Sandbox Code Playgroud)

免责声明:虽然我在21世纪初对其进行了多次编码,但为了这个答案,我编写了上面的代码,虽然我用g ++测试它,但它可能不一定是完美的.


(1)参见Basile Starynkevitch关于另一种可能性的讨论的答案,即g ++特定的内在函数__builtin_unreachable.


dje*_*lin 13

它总是会失败.这就是它.它总是会失败的原因是,只要x = 5,"assert(x == 5)"就会成功.

如果你要求一个应用程序,那么你会把它放在真正不应该发生的代码块中.

switch(suit) {
  case CLUB:
  case DIAMOND:
  case HEART:
  case SPADE:
  // ...
  default:
    assert(0);
 }
Run Code Online (Sandbox Code Playgroud)

  • @SmithWestern零是一个始终为假的条件,就像"现在的时间就是现在"是一个始终为真的条件. (2认同)
  • 那应该是“每当 x != 5” (2认同)
  • @SmithWestern在C中没有布尔类型,因此"false"为零,"true"为非零值 (2认同)

eml*_*lai 9

是的,它总会失败.

assert(0)或者assert(false)通常用于标记无法访问的代码,以便在调试模式下发出诊断消息,并在实际到达所谓的无法访问时中止程序,这清楚地表明程序没有按照我们的想法行事.

  • 不是"无法访问",而是"如果我的代码中存在错误,则无法访问".无法访问无法访问的代码."只有在我的代码中存在错误才能无法访问"经常达成:-( (2认同)

Bas*_*tch 5

除了其他答案(尤其是这个)之外,如果您使用的是最近的GCC(或Clang),您可能会考虑使用一些GCC 内置,特别 是而不是.__builtin_unreachable()assert(0)

有一些区别:首先,assert可以使用 禁用-DNDEBUG。并将__builtin_unreachable改变编译器优化代码的方式。

当然,有些编译器不知道__builtin_unreachable.

您还可以考虑调用一些[[noreturn]]C++ 函数(在 C++11 或更好的版本中) - 或GCC__attribute__((noreturn))例如abort()

顺便说一句,assert(0) 并不完全像抛出一些异常(因为可以捕获异常)

  • _builtin_unreachable 是非常非常不同的东西。断言(0)意味着“如果到达此代码,则我的代码中存在错误;如果到达,请告诉我和/或停止程序”。__builtin_reachable 的意思是“这段代码不可访问。编译器,你可能不够聪明,无法弄清楚它,但相信我,它是不可访问的”。编译器将删除以下代码,因为它不可访问,如果函数返回但没有返回值,则不会抱怨,因为返回不可访问,等等。 (2认同)