首页 > *nix技术, 内核技术 > 编译阶段的assert()

编译阶段的assert()

2012年11月13日 发表评论 阅读评论 1,352 次浏览

翻内核代码,看到几个有意思的东东,然后Stackoverflow查了一把BUILD_BUG_ON(不知从何时起,我遇到问题都是先Stackoverflow,找不到再Google,也许是因为在Stackoverflow里,如果能找到答案,那么答案会更明确&详细吧),于是有此文章。

这几个宏从哪个内核版本开始引入不得而知,不过我这里是linux-3.2\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); }))

/**
 * BUILD_BUG_ON - break compile if a condition is true.
 * @condition: the condition which the compiler should know is false.
 *
 * If you have some code which relies on certain constants being equal, or
 * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
 * detect if someone changes it.
 *
 * The implementation uses gcc's reluctance to create a negative array, but
 * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
 * to inline functions).  So as a fallback we use the optimizer; if it can't
 * prove the condition is false, it will cause a link error on the undefined
 * "__build_bug_on_failed".  This error message can be harder to track down
 * though, hence the two different methods.
 */
#ifndef __OPTIMIZE__
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#else

英文注释很明朗,这几个宏用于做编译阶段(注意:这很重要,因为它和通常的利用assert()类函数在运行时进行条件检测是完全不同的)的条件判断,比如宏BUILD_BUG_ON_ZERO,如果表达式e为真,那么在编译阶段就会收到对应的错误提示,并且中止继续编译:

/home/gqk/t # cat -n t.c
     1  #include <stdio.h>
     2
     3  #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
     4
     5  int main(){
     6          BUILD_BUG_ON_ZERO(1);
     7          printf("Test\n");
     8  }
/home/gqk/t # gcc t.c
t.c: In function 'main':
t.c:6: error: negative width in bit-field '<anonymous>'
/home/gqk/t #

下面就来看看为什么会这样,对BUILD_BUG_ON_ZERO(1)进行宏展开为(具体请看参考链接1):
(sizeof(struct { int:-!!(1); }))
!(1):非1即为0。
!!(1):非非1即为1。
-!!(1):负1乘以非非1即为负1。
struct { int:-!!(1); }:也就是struct { int:-1; },结构体字段中的冒号,我们知道是位域,表示该字段要占多少bit位,明显,这个位数不可能是负数,所以编译出错,这也符合gcc给出的错误提示信息:negative width in bit-field。

e为其它非零值的情况与上类似,而对于e为0的情况,那么最终的展开结果为struct { int:0; },这表示位域位数占零位,这是可以的(具体请看参考链接2)。

宏BUILD_BUG_ON_NULL无需多说,再看BUILD_BUG_ON也是一样,如果表达式condition为非零,那么数组元素将为-1个,而这明显也是不允许的。

对于位域字段位数占零位的情况,此时位域字段必须是匿名的,否则将提示错误:

t.c:11: error: zero width for bit-field 'k'

这个应该主要用在结构体字段对齐上,但估计这种实际需求会比较少。

完全参考:
1,http://stackoverflow.com/questions/9229601/what-is-in-c-code
2,http://stackoverflow.com/questions/4297095/practical-use-of-zero-length-bitfields
3,http://stackoverflow.com/questions/599365/what-is-your-favorite-c-programming-trick

转载请保留地址:http://lenky.info/archives/2012/11/13/2020http://lenky.info/?p=2020


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.