我在/usr/include/linux/kernel.h中遇到了这个奇怪的宏代码:
/*如果条件为true,则强制执行编译错误,但也会生成
结果(值为0,类型为size\t),因此可以使用表达式
e、 g.在结构初始值设定项中(或在其他任何地方使用逗号表达式)
不允许)*/
#在0(e)(sizeof(struct{int:-!!(e);}))上定义构建错误
#在空(e)((void*)sizeof(struct{int:-!!(e);})上定义构建BUG)
什么是:-做什么
实际上,这是一种检查表达式e是否可以计算为0的方法,如果不能,则检查生成是否失败
宏有点命名错误;它应该更像是BUILD\u BUG\u或\u ZERO
,而不是…ON\u ZERO
。(关于这是否是一个令人困惑的名字,偶尔会有讨论)
你应该这样读:
sizeof(结构{int:-!!(e);}))
-
(e)
:计算表达式e
-
!!(e)
:逻辑求反两次:0
如果e==0
;否则1
-
-!!(e)
:对步骤2中的表达式进行数字求反:0
,如果它是0
;否则-1
-
struct{int:-!!(0);}-->;struct{int:0;}
:如果它是零,那么我们声明一个具有宽度为零的匿名整数位字段的结构。一切正常,我们照常进行 -
struct{int:-!!(1);}-->;struct{int:-1;}
:另一方面,如果它不是零,那么它将是一些负数。使用负宽度声明任何位字段都是编译错误
因此,我们要么在结构中得到宽度为0的位字段,这很好,要么得到宽度为负的位字段,这是一个编译错误。然后我们取该字段的sizeof
,得到一个宽度合适的size\u t
(在e
为零的情况下,该值为零)
有人问:为什么不直接使用断言?
?
基思莫在这里的回答有很好的回应:
这些宏实现编译时测试,而assert()是运行时测试
完全正确。您不想在运行时检测到内核中的问题,这些问题可能在更早的时候就被发现了!它是操作系统的关键部分。无论在编译时可以检测到多大程度的问题,那就更好了