错误: 非法的表达式开始_虽然这两个C语言宏定义很简单,但是能在程序运行前找到错误代码...

今天翻看 Linux 内核源代码时,发现两行非常有意思的C语言代码,如下:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
064216f2c45af24cf5a35461ae16171a.png

有意思的宏

这两行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 宏的适用范围就很小了。

c2086e777ee668c5e615cf3bb82c468a.png

现在明白了

现在明白了,!!(e) 的值要么是 0,要么是 1。再考虑前面的负号,-!!(e) 要么是 0,要么是 -1,即对于 int:-!!(e) 来说,只有两种情况:

int: 0// 或者int: -1

显然,位域的长度不能是负数,所以如果表达式 e 为真时,宏 BUILD_BUG_ON_XX 就是非法的了,在编译阶段就会报错

“编译时”和“运行时”

从某种程度上来看,上述C语言宏可以看作是编译时的 assert()。有读者可能会问,既然如此,为什么不直接使用 assert(),而是花大力气自定义呢?

82c9b9ff180fc4ac4678f0199517d914.png

为什么不直接使用 assert(),而是花大力气自定义呢?

读者应该注意“编译时”这个关键词,BUILD_BUG_ON_XX 宏在编译阶段就可以检查错误,这就能确保程序员能够在程序运行之前发现错误,并修改相关的C语言代码。与之对应的, assert() 只能在程序运行时检查错误,程序运行时出错就麻烦了,至少需要程序员编写相应的错误处理逻辑C语言代码。

如果能够在程序开发阶段发现错误,是多么美好的一件事啊。
4c99db48f858e951de849c814ae77e34.png

如果能够在程序开发阶段发现错误,是多么美好的一件事啊。

那 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语言语法的实现编译时判断的技巧有很多种,例如:

9e61650b62a6c4d3b1b96e9c30f0c4a7.png

借助C语言语法的实现编译时判断的技巧

它们的原理和作用都是类似的,留给读者自己分析了,这里不再赘述。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux下数据库时间格式,Java编程时间格式与数据库中时间格式转化

关于编程语言中的时间格式和关系型数据中的中时间格式问题的转化一直都是个简单而又不得不权衡的问题&#xff0c;这牵扯到数据库设计和SQL编程和应用程序中时间格式数据的处理的编程&#xff0c;两者总能够交缠在一起。关于Java中的时间格式和数据库中的时间格式转换在这里先写…

python函数作用域与闭包_python基础-08-内置函数、作用域、闭包、递归

python基础-内置函数、作用域、闭包、递归1.常见的内置函数常见的内置函数:查看内置函数&#xff1a;print(dir(__builtins__))常见函数type() 数据类型print() 打印help()查看方法详细用法id() 查看内存地址range() 求值范围len 求长度min 求最小值max 求最大值sorted 排序rev…

linux 配置trac界面显示为中文,安装back|track 5 r3并配置中文界面简单教程

最近更新&#xff1a;29th 4月, 2013最近对bt比较感兴趣&#xff0c;看到不少朋友说&#xff0c;bt早都出10了11了我说我怎么就不知道。官方网站打开一看&#xff0c;果然还是BT5&#xff0c;不过已经r3了。听说现在BT5的支持已经很好了&#xff0c;于是也就下载了一个&#xf…

ue4玻璃材质_UE4-材质

本文中&#xff0c;我们将首先讨论基于物理的渲染&#xff0c;什么是材质域&#xff0c;什么是材质&#xff0c;什么是材质实例&#xff0c;什么是主材质&#xff0c;我们将讨论材质的一些建议和禁忌。最后&#xff0c;我们将了解一些材质概念&#xff0c;你可以将其用于各类项…

suse linux11 改ip,suse11如何修改hostname[Linux基础]

1.修改当前的hostname可以用hostname myname此时只是修改了内存内部的&#xff0c;下次启动又恢复了2.机器在启动的时候会调用/etc/rc.d/boot.localnet脚本看后面的附录&#xff0c;这个脚本会判断当前的$HOSTNAME变量是否设置&#xff0c;没有设置就会读取/etc/HOSTNAME来设置…

为啥linux分区是nvme0n1,NAS 篇五:尝试达成最终目标: 黑裙+万兆网卡+Nvme 存储空间的实现与测试...

NAS 篇五&#xff1a;尝试达成最终目标&#xff1a; 黑裙万兆网卡Nvme 存储空间的实现与测试2020-01-18 18:49:2346点赞248收藏80评论创作立场声明&#xff1a;1. 本系列文章讨论NAS与局域网&#xff0c; 请小编高抬贵手不要分类到无线网络去2. 如果你读了开头&#xff0c; 有“…

检查虚ip跟实ip之间网络问题_虚电路有哪些特点 虚电路原理介绍【详解】

虚电路,虚电路的特点,虚电路的原理是什么?虚电路是交换网络(ATM、帧中继、IP或因特网)上两个终端站之间的点对点通信链路。虚电路的设计是在交换网络上仿真物理电路的特性。家中与电话公司中心局之间的模拟电话线路就是物理电路的例子。它是专用于单个呼叫的物理线路,没有其他…

linux 常用参数,Linux 常用命令及参数整理

1.. cat -t2.. ls -t -u3..uniq -c-u -d4..sort -k-u -t -f -n5.. tail head6.. rpm -q -ql -qf -qc7.. find8.. sz 从服务器上下载文件9.. du 和 df 命令区别1.. cat-t 相当于 -vT 作用是显示文件中的tab符号&#xff0c;通常和-v参数一起使用。[rootwatchout2 ~]# cat -t…

固态硬盘上安装centos_自己动手丰衣足食 手把手教你安装M.2固态硬盘

为了追求更快的速度、更好的性能&#xff0c;很多用户都为电脑升级或者更换了M.2固态硬盘。但是&#xff0c;M.2固态硬盘买好了&#xff0c;安装对大部分人来说却是个难题……因此&#xff0c;好多老铁通过微信后台联系小星&#xff0c;想了解一下M.2固态硬盘的安装教程。OK&am…

linux美元符号切换为井号,struts2 (# % $)井号,百分号,美元符号的含义和使用方法举例...

struts2 (# % $)井号&#xff0c;百分号,美圆号的含义和使用举例。struts2 OGNL&#xff0c;struts2 表达式语言&#xff0c;OGNL(Object-Graph Navigation Language)&#xff0c;可以方便地操作对象属性的开源表达式语言。本文提要&#xff1a;(1)Struts2 #&#xff0c;表达式…

创建txt文件指令_Linux云计算教程全套视频合集:WORKDIR 指令讲解

WORKDIR 指令用于声明当前的工作目录&#xff0c;以后各层的当前目录就被改为指定的目录。格式为 WORKDIR <工作目录路径>。如该目录不存在&#xff0c;WORKDIR 会帮你建立目录。再次强调&#xff01;不要以为编写 Dockerfiel 是在写 shell 脚本。下面是一个错误示例&…

linux通过yum安装nginx,Linux下yum安装nginx教程

本文教程为大家分享了linux下yum安装nginx的详细过程&#xff0c;供大家参考&#xff0c;具体内容如下第一步&#xff0c;在/etc/yum.repos.d/目录下创建一个源配置文件nginx.repo&#xff1a;cd /etc/yum.repos.d/vim nginx.repo填写如下内容&#xff1a;[nginx]namenginx rep…

python怎么写出来的_如何写出优雅又地道的Python代码?【转载】

在Python社区文化的浇灌下&#xff0c;演化出了一种独特的代码风格&#xff0c;去指导如何正确地使用Python&#xff0c;这就是常说的pythonic。一般说地道(idiomatic)的python代码&#xff0c;就是指这份代码很pythonic。Python的语法和标准库设计&#xff0c;处处契合着pytho…

linux awk if 多个条件,linux shell awk 流程控制语句(if,for,while,do)详细介绍

在linux awk的 while、do-while和for语句中允许使用break,continue语句来控制流程走向&#xff0c;也允许使用exit这样的语句来退出。break中断当前正在执行的循环并跳到循环外执行下一条语句。if 是流程选择用法。 awk中&#xff0c;流程控制语句&#xff0c;语法结构&#xf…

vba 自动排序_给VBA字典键值排序,并提取需要的数据

未知的领域很广、风景很美&#xff0c;不要蜷缩在一小块自认为天堂的世界里。待到暮年时安于自欺欺人&#xff0c;要努力提高自己&#xff0c;学习是一件很辛苦的事。要有一颗充满生机的心&#xff0c;把握现在&#xff0c;这才是进取。机会总在等待中出现&#xff0c;越是有意…

linux 带缓存的fwrite,文件IO编程之(六):基于流缓冲 fopen,fwrite,fput

标准IO开发前面分析的文件IO编程都是基于文件描述符的。这些都是基本的IO控制&#xff0c;是不带缓存的。这里要讨论的IO操作是基于流缓冲的&#xff0c;它是符合ANSIC的标准IO处理。标准IO提供流缓冲的目的是尽可能减少使用read和write调用的数量。标准IO提供了3种类型的缓冲存…

vba 提取 json某个值_利用VBA字典,提取两列数据的重复值

大家好&#xff0c;今日我们继续讲解VBA数组与字典解决方案&#xff0c;今日讲解第52讲&#xff1a;利用字典&#xff0c;提取两列数据重复值。有人讲:字典是VBA中最为精华的部分,持这种观点的人肯定有自己的道理,确实,利用字典可以给我的代码带来很大的方便之处,今日我讲解的是…

Linux中存储相关的命令,Linux存储管理命令与HAB相关命令

首先了解Linux中的设备命名规则&#xff1a;在安装和使用Linux的过程中&#xff0c;您必然会接触到不少像hda1、ttyS0、eth0这样的设备名称。在Linux中&#xff0c;每个设备必须在它的驱动程序控制下运行&#xff0c;驱动程序则与/dev目录下的特殊文件联系在一起&#xff0c;尽…

红外倒车雷达原理图_硅光电倍增管 (SiPM) 直接飞行时间 (dToF) 激光雷达平台为工业测距应用提供现成的设计...

点击蓝字关注我们请私信我们添加白名单如果您喜欢本篇文章&#xff0c;欢迎转载&#xff01;推动高能效创新的安森美半导体 (ON Semiconductor&#xff0c;美国纳斯达克上市代号&#xff1a;ON)&#xff0c;推出了由该公司硅光电倍增管 (SiPM) 技术实现的单点直接飞行时间 (dTo…

linux中nslookup命令功能,nslookup

a,最简单的方法[rootrudder ~]# nslookup baidu.comServer: 8.8.8.8Address: 8.8.8.8#53Non-authoritative answer:Name: baidu.comAddress: 123.125.114.144Name: baidu.comAddress: 220.181.111.85Name: baidu.comAddress: 220.181.111.86nslookup&#xff0c;交互方式&#…