assert(0) 是什么意思?

What does assert(0) mean?

我在一次考试中遇到了这样的问题,但我仍然不太确定如何回答。我知道断言是测试程序的方法,但是我不太确定 assert(0) 正在检查什么。这是一个技巧问题吗?它总是会失败,但我不明白为什么。它在检查什么?

任何解释都很好,谢谢。

总是会失败。差不多就是这样。它总是会失败,原因与 "assert(x == 5)" 会在 x = 5 时成功相同。

如果您要申请,那么您会把它放在确实不应该发生的代码块中。

switch(suit) {
  case CLUB:
  case DIAMOND:
  case HEART:
  case SPADE:
  // ...
  default:
    assert(0);
 }

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

C99 §7.2/2:

The assert macro puts diagnostic tests into programs; it expands to a void expression. When it is executed, if expression (which shall have a scalar type) is false (that is, compares equal to 0), the assert macro writes information about the particular call that failed (including the text of the argument, the name of the source file, the source line number, and the name of the enclosing function — the latter are respectively the values of the preprocessing macros __FILE__ and __LINE__ and of the identifier __func__) on the standard error file in an implementation-defined format. It then calls the abort function.


assert(0) 中,0 被解释为 false,所以这个断言总是会失败,或者 fire,当断言检查是上。

因此它断言

“The execution will never reach this point.”

在实践中,很难让编译器对执行达到或未达到给定点闭嘴。通常编译器会首先抱怨执行可能到达函数末尾而没有返回值。添加一个 assert(0) 应该可以理想地解决这个问题,但是编译器可能会抱怨 assert,或者不承认它说你已经很清楚它试图警告什么。

一个 (1) 可能的措施是在那个时候也抛出异常:

auto foo( int x )
    -> int
{
    if( x == 1 ) { return 42; }
    assert( 0 ); throw 0;       // Should never get here!
}

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


要关闭 assert 断言检查,您可以在包含 <assert.h>.

之前定义符号 NDEBUG

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

C++11 §17.6.2.2/2:

A translation unit may include library headers in any order (Clause 2). Each may be included more than once, with no effect different from being included exactly once, except that the effect of including either <cassert> or <assert.h> depends each time on the lexically current definition of NDEBUG.

上面讨论的 double-whammy 的合理定义同样可以依赖 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

免责声明:虽然我在 2000 年代初期编写了很多次代码,但我编写上面的代码只是为了这个答案,虽然我确实使用 g++ 对其进行了测试,但它不一定是完美的。


(1) 请参阅 Basile Starynkevitch's answer 以了解另一种可能性的讨论,即 g++ 特定的内在函数 __builtin_unreachable

是的,总是会失败。

assert(0)assert(false)通常用于标记无法访问的代码,以便在调试模式下发出诊断消息并中止程序假设无法到达的地方实际上已经到达,这是一个明确的信号,表明程序没有按照我们的想法去做。

添加 到其他答案(特别是 one), if you are using a recent GCC (or Clang), you might consider using some GCC builtin,特别是 __builtin_unreachable() 而不是 assert(0)

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

当然有些编译器不知道__builtin_unreachable

您还可以考虑调用一些 [[noreturn]] C++ 函数(在 C++11 或更高版本中)- 或 __attribute__((noreturn)) for GCC,例如 abort()

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