Namespaces
Variants

assert

来自 zh.cppreference.net
定义于头文件 <cassert>
禁用断言
#define assert(condition) ((void)0)
(1) (until C++26)
#define assert(...)       ((void)0)
(since C++26)
启用断言
#define assert(condition) /* unspecified */
(2) (until C++26)
#define assert(...)       /* unspecified */
(since C++26)

宏 assert 的定义依赖于另一个宏 NDEBUG,该宏不由标准库定义。

1) 如果 NDEBUG 在源代码中包含了 <cassert> 或 <assert.h> 的位置被定义为宏名,则断言被禁用:assert 不执行任何操作。
2) 否则,断言被启用:

assert 检查其参数(必须具有标量类型):

  • 如果该参数比较不等于零,则没有进一步的影响。
  • 否则,assert 在标准错误流上创建诊断并调用 std::abort()。
(until C++26)

assert 将诊断测试放入程序中,并展开为类型 void 的表达式。__VA_ARGS__ 被求值并按语境转换为 bool:

  • 如果求值结果为 true,则没有进一步的影响。
  • 否则,assert 在标准错误流上创建诊断并调用 std::abort()。
(since C++26)

诊断信息具有实现定义的格式,但始终包含以下信息:

  • 的文本 condition
(until C++26)
  • #__VA_ARGS__
(since C++26)

表达式 assert(E) 保证是一个 常量子表达式,如果满足以下任一条件:

  • NDEBUG 在定义或重新定义 assert 的点被定义,或者
  • E, 按语境转换为 bool,是一个求值结果为 true 的常量子表达式。
(since C++11)

参数

条件 - 标量类型的表达式

注释

由于 assert 是 函数式宏 ,实参中所有未被括号保护的逗号都会被解释为宏参数分隔符。此类逗号常出现于模板实参列表和列表初始化中:

assert(std::is_same_v<int, int>);        // 错误:assert 不接受两个参数
assert((std::is_same_v<int, int>));      // 正确:单个参数
static_assert(std::is_same_v<int, int>); // 正确:非宏
std::complex<double> c;
assert(c == std::complex<double>{0, 0});   // 错误
assert((c == std::complex<double>{0, 0})); // 正确
(C++26 前)

目前没有标准化接口来为 assert 错误添加额外信息。一种可移植的包含方式是利用 逗号运算符 (前提是该运算符未被 重载 ),或结合字符串字面值使用 && 运算符:

assert(("There are five lights", 2 + 2 == 5));
assert(2 + 2 == 5 && "There are five lights");

Microsoft CRT 中 assert 的实现不符合 C++11 及后续修订标准,因为其底层函数 ( _wassert ) 既不接收 __func__ 也不接收等效替代项。

自 C++20 起,诊断消息所需的值也可通过 std::source_location::current() 获取。

尽管 C23/C++26 中对 assert 的变更在形式上不属于缺陷报告,但 C 标准委员会 建议 实现者将该变更向后移植到旧模式中。

示例

#include <iostream>
// 取消注释以禁用 assert()
// #define NDEBUG
#include <cassert>
// 使用 (void) 来消除未使用警告
#define assertm(exp, msg) assert((void(msg), exp))
int main()
{
    assert(2 + 2 == 4);
    std::cout << "检查点 #1\n";
    assert((void("void 有助于避免'未使用值'警告"), 2 * 2 == 4));
    std::cout << "检查点 #2\n";
    assert((010 + 010 == 16) && "另一种添加断言消息的方法");
    std::cout << "检查点 #3\n";
    assertm((2 + 2) % 3 == 1, "成功");
    std::cout << "检查点 #4\n";
    assertm(2 + 2 == 5, "失败"); // 断言失败
    std::cout << "执行继续经过最后一个断言\n"; // 无输出
}

可能的输出:

检查点 #1
检查点 #2
检查点 #3
检查点 #4
main.cpp:23: int main(): Assertion `((void)"失败", 2 + 2 == 5)' failed.
Aborted

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用版本 发布时行为 正确行为
LWG 2234 C++11 assert 不能在常量表达式中使用 可以使用

参见

contract_assert 语句 (C++26) 在执行期间验证内部条件
static_assert 声明 (C++11) 执行编译时断言检查
导致程序异常终止(不进行清理)
(函数)
C 文档 关于 assert