【赤石C++】BUILD_BUG_ON 宏

BUILD_BUG_ON

考虑一个问题:在没有 static_assert 的年代,如何确保在编译期抛出错误?

我们知道,在 C 语言中,无法创建负长度数组且数组长度会在编译期求值

1
2
3
4
5
// 无法创建负长度数组
char a[-1];

// 数组长度编译期求值
char a[2 * 3]; // sizeof(a) == 6

所以,利用这个特性就可以实现一个简易的 static_assert,当条件不满足时创建一个负数长度数组保证在编译期抛出错误

1
#define my_static_assert(condition) char a[condition ? 1 : -1]

但引入了几个新的问题:命名空间污染和运行时开销

C 语言不支持匿名数组,声明数组时必须指定变量名(声明必须绑定到标识符),会造成命名空间污染

1
2
// 不支持匿名数组,这是非法语句
char[1];

此外,在编译器优化能力不足时,多余的数组还可能导致多占用栈空间造成额外的运行时开销

解决方法是使用 sizeof 包裹,我们知道,sizeof 后面可以跟一个类型名(更准确的说法是“类型抽象声明符”),所以 sizeof(char[1]) 是合法语句,因为这里的 char[1] 并不是在创建数组,而是在描述一个类型,sizeof 只关心这个类型的大小,不需要创建实际对象

1
2
// 合法语句
sizeof(char[1]);

不会造成命名空间污染,不会造成运行时开销(sizeof 也是编译期求值),Linux 内核的 BUILD_BUG_ON 就是这样实现的

1
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

首先,!!(condition) 把任意表达式强制转为 0 或 1(布尔化)

当表达式为 1 时,宏被展开为 sizeof(char[-1]),否则被展开为 sizeof(char[1])

1
2
3
4
5
// 正常编译
sizeof(char[1]);

// 抛出错误
sizeof(char[-1]);

【赤石C++】BUILD_BUG_ON 宏
https://crackme.net/articles/bulid_bug_on/
作者
Brassinolide
发布于
2026年2月13日
许可协议