Linux Kernel 代码艺术——编译时断言【转】
转自:http://www.cnblogs.com/hazir/p/static_assert_macro.html
本系列文章主要写我在阅读Linux内核过程中,关注的比较难以理解但又设计巧妙的代码片段(不关注OS的各个模块的设计思想,此部分我准备写在“深入理解Linux Kernel” 系列文章中),一来通过内核代码复习一下C语言及汇编语言的语法,二来学习内核开发大牛们书写代码的风格及思路。
在内核文件 include/linux/bug.h中,有下面两行的宏定义:
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); })) |
以第一个分析,它表示的是:检查表达式e是否为0,为0编译通过且返回0;如果不为0,则编译不通过。
可能从这个宏的名字上看可能容易理解错,或者改为“BUILD_BUG_OR_ZERO”更好,关于这个的讨论有人也提交这个patch(http://lkml.indiana.edu/hypermail/linux/kernel/0703.1/1546.html),但未能被社区接受。我们且不管这个宏定义名字怎样,来逐步分析一下这个宏是如何来实现的:
sizeof(struct { int : –!!(e); } ))
1. (e): 表达式e的声明
2. !!(e): 对e的结果进行两次求非。即如果e开始是0的话,结果就是0;如果e不为0,则结果为1。
3. –!!(e): 再乘以-1。如果第2步结果为0,则仍为0;否则结果为-1。
4. struct { int : –!!(0); } --> struct { int : 0; } : 如果e的结果为0,则我们声明一个结构体拥有一个int型的数据域,并且规定它所占的位的个数为0。这没有任何问题,我们认为一切正常。
5. struct { int : –!!(1); } --> struct { int : –1; } : 如果e的结果非0,结构体的int型数据域的位域将变为一个负数,将位域声明为负数这是一个语法的错误。
6. 现在要么结果为声明了一个位域为0的结构体,要么出现位域为负数编译出错;如果能正确编译,然后我们对该结构体进行sizeof操作,得到一个类型为size_t的结果,值为0。
再总结一下,BUILD_BUG_ON_ZERO(e) 表示的就是若表达式e结果为0,则编译通过,该宏的值也为0;若表达式e的结果不为0,则编译不通过。
这会让人联想到C语言中 assert 宏的用法:
void assert(int expression);
如果参数expression 计算的结果为0,它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行;否则断言成立,继续执行。
我们讨论的宏与assert本质区别在于,我们的宏在编译时进行测试,而assert宏是在运行时测试。我们希望能尽早地捕获到我们编译时的错误,而不是推迟到运行时。我管这种宏用法叫做“编译时断言”,assert为“运行时断言”。
理解了上面之后,再来看看第二个BUILD_BUG_ON_NULL(e)宏,与第一个类似,用来在编译时断言e是否为NULL,若是这个宏返回(void *)0 (即NULL,与第一个宏的区别);不为NULL时编译出错。
除了上面的两个编译时断言之外,include/linux/bug.h文件中还有另几个大家可以思考表示何意,如:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
含义可以参考文件中宏定义的注释说明。
-------------------------------------完--------------------------------
参考资料:
http://blog.csdn.net/jiyucn/article/details/862085 C语言中关于结构体位域的详细说明
http://blog.csdn.net/jiyucn/article/details/862062 C语言中sizeof相关问题
http://www.cplusplus.com/reference/cassert/assert/ assert用法说明
http://stackoverflow.com/questions/9229601/what-is-in-c-code 问题及解答均来源于Stackoverflow
本博客的内容如果没有标注转载字样,均属个人原创!欢迎学习交流,如果觉得有价值,欢迎转载,转载请注明出处,谢谢!
邮箱:haifenglinying#yahoo.cn (#->@)
个人主页:www.hazirguo.com
Linux Kernel 代码艺术——编译时断言【转】的更多相关文章
- Linux Kernel 代码艺术——编译时断言
本系列文章主要写我在阅读Linux内核过程中,关注的比较难以理解但又设计巧妙的代码片段(不关注OS的各个模块的设计思想,此部分我准备写在“深入理解Linux Kernel” 系列文章中),一来通过内核 ...
- Linux Kernel代码艺术——系统调用宏定义
我们习惯在SI(Source Insight)中阅读Linux内核,SI会建立符号表数据库,能非常方便地跳转到变量.宏.函数等的定义处.但在处理系统调用的函数时,却会遇到一些麻烦:我们知道系统调用函数 ...
- Linux Kernel代码艺术——数组初始化
前几天看内核中系统调用代码,在系统调用向量表初始化中,有下面这段代码写的让我有点摸不着头脑: const sys_call_ptr_t sys_call_table[__NR_syscall_max+ ...
- Linux Kernel代码艺术——数组初始化【转】
转自:http://www.cnblogs.com/hazir/p/array_initialization.html 前几天看内核中系统调用代码,在系统调用向量表初始化中,有下面这段代码写的让我有点 ...
- 【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介
作者 : 韩曙亮 转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827 一. Linux 内核简介 1. 内核功能简介 ...
- Linux+CLion+树莓派远程编译时,Cmake编译出现undefined reference to 'dlopen'的解决办法
在Clion中链接讯飞的语音库并传至树莓派上编译时,出现如下错误. undefined reference to `dlopen' undefined reference to `dlclose' u ...
- 使用linux kernel代码编译perf工具
环境:Qemu + ARMv8 perf是一款综合性分析工具,大到系统全局性性能,再小到进程线程级别,甚至到函数及汇编级别. 在内核源码目录下执行编译脚本: #!/bin/bash cross_com ...
- Linux+CLion+树莓派远程编译时,Cmake编译出现undefined reference to 'pthread_create'的解决办法
在CLion中开发讯飞的linux语音库时编译出现以下问题: undefined reference to 'pthread_create' CLion的cmake配置:修改CMakeLists.tx ...
- linux下C/C++编译时系统搜索 include 和 链接库 文件路径的指定
C/C++程序在linux下被编译和连接时,GCC/G++会查找系统默认的include和link的路径,以及自己在编译命令中指定的路径.自己指定的路径就不说了,这里说明一下系统自动搜索的路径. ...
随机推荐
- 【BZOJ4503】两个串(FFT)
[BZOJ4503]两个串(FFT) 题面 给定串\(S\),以及带通配符的串\(T\),询问\(T\)在\(S\)中出现了几次.并且输出对应的位置. \(|S|,|T|<=10^5\),字符集 ...
- SharePoint 2013 APP 开发示例 系列
SharePoint 2013 APP 安全: SharePoint 2013 APP 开发示例 (一)List 读写 SharePoint 2013 APP 开发示例 (二)获取用户信息 Share ...
- emWin 文字图形同时刷新导致图形显示异常
@2018-7-10 实现目标 一 BUTTON 控制文字图形的刷新切换,具体为 BUTTON 初次按下,文字显示为 “开始” .填充圆显示为绿色,再次按下,文字显示为 “停止” .填充圆显示为红色 ...
- 树链剖分&dfs序
树上问题 很多处理区间的问题(像是RMQ,区间修改).可以用线段树,树状数组,ST表这些数据结构来维护.但是如果将这些问题挪到了树上,就不能直接用这些数据结构来处理了.这时就用到了dfs序和树链剖分. ...
- sscanf,sprintf 通过字符串与其它类型进行方便快捷的输入和输出
http://c.biancheng.net/cpp/html/296.html 头文件:#include <stdio.h> sscanf()函数用于从字符串中读取指定格式的数据,其原型 ...
- Windows7 64下搭建Caffe+python接口环境
参考链接: http://www.cnblogs.com/yixuan-xu/p/5858595.html http://www.cnblogs.com/zf-blog/p/6139044.html ...
- R语言 画图roc
这才是我要的滑板鞋~~~~~ #glm模型glm.model=train(y~.,data=data_train, method="glm", metric="ROC&q ...
- Winform下载文件并显示进度条
本来是要研究怎样判断下载完成,结果找到这个方法,可以在这个方法完成之后提示下载完成. 代码如下: using System; using System.Collections.Generic; usi ...
- IOS 获取系统通讯录中的联系人信息
- (IBAction)getAllContactFromSystem { ABAddressBookRef ab = ABAddressBookCreateWithOptions(NULL, NUL ...
- 为什么要用dubbo,dubbo和zookeeper关系
为什么要用dubbo? 当网站规模达到了一定的量级的时候,普通的MVC框架已经不能满足我们的需求,于是分布式的服务框架和流动式的架构就凸显出来了. 单一应用架构 当网站流量很小时,只需一个应用 ...