今天查看Linux内核源码,出现一个很奇怪的用法。可以在静态编译期的断言。
1. 内核源码kernel.h
BUILD_BUG_ON_ZERO
判断表达式非零值编译器报错;BUILD_BUG_ON_NULL
判断表达式指针地址非空报错。1
2
3
4
5
6/* 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). */
2. 源码解析
(e)
:计算表达式e;!!(e)
:逻辑否定两次;-!!(e)
:0如果是0; 否则-1;struct{int: -!!(0);} --> struct{int: 0;}
:如果它为零,那么我们声明一个结构,其中包含一个宽度为零的匿名整数位域。这样会编译正常;struct{int: -!!(1);} --> struct{int: -1;}
:如果它不是零,那么它将是一些负数。声明任何具有负宽度的位域是编译错误。- 利用位域的宽度做编译判断,因为任何负数的位域都是错误的。
3. 为什么不使用断言?
- 静态断言宏实现了编译时测试,断言宏assert是一个运行时测试;
- 可以在编译器找出错误。无论在何种程度上,在编译时都可以检测到问题,就更好了。特别是在操作系统的关键部分。