!!“在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); }))
  • (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_t (在e为零的情况下它将为零)。


    有人问: 为什么不使用assert

    keithmo在这里的答案有很好的回应:

    这些宏实现了一个编译时测试,而assert()是一个运行时测试。

    非常正确。 您不希望在运行时检测到您的内核中可能早期发现的问题! 这是操作系统的关键部分。 无论在编译时可以检测到什么程度的问题,都会更好。


    :是一个位域。 至于!! ,这是逻辑双重否定,因此返回0代表假或1代表真。 而-是一个负号,即算术否定。

    这只是一个窍门,让编译器在无效输入上陷入困境。

    考虑BUILD_BUG_ON_ZERO 。 当-!!(e)评估为负值时,会产生编译错误。 否则-!!(e)评估为0,0宽度位域的大小为0.因此,宏评估的值为0的size_t

    在我看来这个名字很弱,因为当输入不为零时,构建实际上会失败。

    BUILD_BUG_ON_NULL非常相似,但产生一个指针而不是int


    有些人似乎将这些宏与assert()混淆。

    这些宏实现一个编译时测试,而assert()是一个运行时测试。

    链接地址: http://www.djcxy.com/p/2017.html

    上一篇: !!" in C code?

    下一篇: Is there a "null coalescing" operator in JavaScript?