C/C++黑魔法-编译期断言

今天查看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). */
    #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
    #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

2. 源码解析

  • (e):计算表达式e;
  • !!(e):逻辑否定两次;
  • -!!(e):0如果是0; 否则-1;
  • struct{int: -!!(0);} --> struct{int: 0;}:如果它为零,那么我们声明一个结构,其中包含一个宽度为零的匿名整数位域。这样会编译正常;
  • struct{int: -!!(1);} --> struct{int: -1;}:如果它不是零,那么它将是一些负数。声明任何具有负宽度的位域是编译错误。
  • 利用位域的宽度做编译判断,因为任何负数的位域都是错误的。

3. 为什么不使用断言?

  • 静态断言宏实现了编译时测试,断言宏assert是一个运行时测试;
  • 可以在编译器找出错误。无论在何种程度上,在编译时都可以检测到问题,就更好了。特别是在操作系统的关键部分。