Namespaces
Variants

assert

From cppreference.net
定义于头文件 <cassert>
禁用断言
(1)
#define assert(condition) ((void)0)
(C++26 前)
#define assert(...)       ((void)0)
(C++26 起)
启用断言
(2)
#define assert(condition) /* 未指定 */
(C++26 前)
#define assert(...)       /* 未指定 */
(C++26 起)

assert 的定义取决于另一个宏 NDEBUG ,该宏并非由标准库定义。

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

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

  • 如果参数比较不等于零,则无进一步效果。
  • 否则, assert 在标准错误流上创建诊断信息并调用 std::abort()
(直至 C++26)

assert 向程序中插入诊断测试并展开为 void 类型的表达式。 __VA_ARGS__ 被求值并 上下文转换为 bool

  • 如果求值结果为 true ,则无进一步效果。
  • 否则, assert 在标准错误流上创建诊断信息并调用 std::abort()
(自 C++26 起)

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

  • condition 的文本内容
(直至 C++26)
  • #__VA_ARGS__
(自 C++26 起)

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

  • assert 最后被定义或重新定义的位置已定义 NDEBUG ,或
  • E 上下文转换为 bool 后,是计算结果为 true 的常量子表达式。
(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