c - 在C 代码 “:-!!”是什么?

  显示原文与译文双语对照的内容

我在 /usr/include/linux/kernel.h 中遇到了这个奇怪的宏代码:


/* Force a compilation error if condition is true, but also produce a
 result (of value 0 and type size_t), so the expression can be used
 e.g. in a structure initializer (or where-ever else comma expressions
 aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

什么是 :-?!

时间:

这是,实际上,一种方法来检查是否同时将e 可以对表达式进行计算 0 ;如果不能,以使构建失败。

宏有点拼错了;它应该更像 BUILD_BUG_OR_ZERO,而不是 ...ON_ZERO 。 ( 已经有 偶尔讨论关于是否这是一个令人困惑的名字 。)

你应该这样读取表达式:


sizeof(struct { int: -!!(e); }))

  1. (e): 计算表达式 e

  2. (e): 逻辑上否定两次:0 如果 e == 0 ;否则为 1 。!

  3. -(e): 数字求反:0 如果 e == 0 ;否则为 -1 。!

  4. struct{int: -!!(0);} --> struct{int: 0;} :如果是零,那么我们声明一个具有宽度为零的匿名整数位流的结构。 一切正常,我们照常进行。

  5. struct{int: -!!(1);} --> struct{int: -1;} :另一方面,如果它不零,就可以据此一些负数。 用负宽度声明任何比特是一个编译错误。

所以我们要么在结构中有宽度为 0的比特,要么是宽度为负的比特,这是一个编译错误。 使用适当的宽度然后我们以 sizeof 该字段,所以我们得到了一个


有些人问:为什么不使用 assert

keithmo的应答有一个很好的响应:

这些宏实现了一个compile-time测试,而 assert() 是一个run-time测试。

完全正确。你不希望在运行时检测到你的内核的问题 ! 这是操作系统的关键部分。 在编译时可以发现任何问题,那么就更好了。

: 是一个比特。 对于 ,这是逻辑双重否定,因此返回 0 为false或者 1 为真。! - 是一个减号,换句话说,算术求反。

这只是一个技巧,让编译器在无效的输入上获得 barf 。

考虑 BUILD_BUG_ON_ZERO 。当 -(e) 计算为负值时,会产生编译错误。! 否则,-(e) 计算为 0,0宽度比特的大小为 0.! 因此,宏的计算结果为 size_t,值为 0.

名称在我的视图中很弱,因为当输入为时,生成实际上失败了。

BUILD_BUG_ON_NULL 非常相似,但生成指针而不是 int

它是创建一个大小 0 比特组,如果该条件为 false,但一个大小 -1 ( -1 ) 比特组如果这里条件为真/non-zero 。! 在前一种情况下,没有错误,该结构用一个int成员初始化。 在后一种情况中,有一个编译错误( 当然,也没有创建大小 -1 比特) 。

...