网站首页 > 技术文章 正文
今天翻看 Linux 内核源代码时,发现两行非常有意思的C语言代码,如下:
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
这两行C语言代码有什么含义呢?
要理解这两行C语言代码,关键就是理解 int:-!!(e) ,但是“:-!!”符号看起来很陌生,C语言中似乎并没有这样的符号。其实不是的,“:-!!”这几个符号都是C语言中的基本符号组成的。
首先,不应该将“:”与 int 剥离,所以 int:-!!(e) 应该这么看,int: (-!!(e)),这就清楚了,显然是位域(bitfield)的定义方法,其中 -!!(e) 是位域的长度。
对于 -!!(e),应该将 e 看作是一个条件表达式,此时 !! 符号可以将其转换为布尔值(即0或者1,读者自己思考原因)。在C语言中,非零即可认为是真,因此 2,3,88 等都看看作真。在本例中,定义位域时,长度不应该超过 int 的宽度,所以如果没有 !! 符号,BUILD_BUG_ON_XX 宏的适用范围就很小了。
现在明白了,!!(e) 的值要么是 0,要么是 1。再考虑前面的负号,-!!(e) 要么是 0,要么是 -1,即对于 int:-!!(e) 来说,只有两种情况:
int: 0 // 或者 int: -1
显然,位域的长度不能是负数,所以如果表达式 e 为真时,宏 BUILD_BUG_ON_XX 就是非法的了,在编译阶段就会报错。
“编译时”和“运行时”
从某种程度上来看,上述C语言宏可以看作是编译时的 assert()。有读者可能会问,既然如此,为什么不直接使用 assert(),而是花大力气自定义呢?
读者应该注意“编译时”这个关键词,BUILD_BUG_ON_XX 宏在编译阶段就可以检查错误,这就能确保程序员能够在程序运行之前发现错误,并修改相关的C语言代码。与之对应的, assert() 只能在程序运行时检查错误,程序运行时出错就麻烦了,至少需要程序员编写相应的错误处理逻辑C语言代码。
如果能够在程序开发阶段发现错误,是多么美好的一件事啊。
那 assert() 就没有存在的必要了?暂时还不是,对于 BUILD_BUG_ON_XX 宏中的条件表达式 e,目前的C语言语法只支持常量表达式,对于变量表达式就无能为力了,只能使用 assert(),例如:
int a = 1; BUILD_BUG_ON_ZERO(1<0); // 合法 BUILD_BUG_ON_ZERO(a<0); // 非法 assert(a<0); // 合法
读者可能会问,BUILD_BUG_ON_XX 宏只能判断常量表达式,那它还有什么应用价值呢?毕竟两个常量的对比谁会弄错呢?BUILD_BUG_ON_XX 宏当然有应用价值,而且还挺好用,下一节将结合实例讨论,敬请关注。
事实上,这种借助C语言语法的实现编译时判断的技巧有很多种,例如:
它们的原理和作用都是类似的,留给读者自己分析了,这里不再赘述。
欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。
- 上一篇: 单片机C语言:数据类型,你学会了吗?
- 下一篇: C 语言的类型(c语言的类型有哪几类)
猜你喜欢
- 2024-10-26 C语言、嵌入式项目中一些常用知识及技巧第一弹
- 2024-10-26 C语言编程:最常见 7 道C语言面试题,还是有不少人弄不明白?
- 2024-10-26 初识C语言:简介、环境搭建、第一个HelloWorld
- 2024-10-26 C|volatile关键字使用细节及适用场合
- 2024-10-26 C语言干货:函数知识详解(变量的作用域,全局变量,静态变量)
- 2024-10-26 小白入门C语言20问20答2(新手c语言)
- 2024-10-26 C语言的简单了解及学习2(c语言的入门知识)
- 2024-10-26 C 语言基本语法(c语言的基础语法)
- 2024-10-26 C语言数据怎么描述?最全面解析,C语言基础教学档案!编号零零五
- 2024-10-26 C语言void关键字的高级玩法,6个样例代码告诉你
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)