linux tricks 之 typeof用法.
typeof是gcc的扩展功能,比较简单,是用来取得参数类型,具体可参考gcc官网的解释.
https://gcc.gnu.org/onlinedocs/gcc/Typeof.html
由于Linux代码采用Gcc编译器编译,所以它可以采用Gcc对C语言的扩展特性,以实现高效的代码。其中运用非常广泛的扩展就是复合语句。Gcc把包含在圆括号和大括号双层括号内的复合语句看作是一个表达式,它可以出现在任何允许表达式的地方,而复合语句中可以声明局部变量,以及循环条件判断等复杂处理。而表达式的最后一条语句必须是一个表达式,它的计算结果作为返回值。
int a = ({typeof(a) _a = ; ++_a;});
上例中符合表达式中声明了局部变量_a,而返回值为++_a的结果,所以a的值为1。基于这种扩展,内核可以通过在复合语句中定义局部变量而表面自加自减运算符的副作用问题。内核中的min_t和max_t宏就是这样实现的。
include/linux/kernel.h
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1: __min2; }) #define max_t(type, x, y) ({ \
type __max1 = (x); \
type __max2 = (y); \
__max1 > __max2 ? __max1: __max2; })
尽管多数时候通过使用这类宏,可以避免参数的副作用,但是这会增加内存的开销和执行效率,所以如果能够保证参数不存在副作用,那么使用通常的如下定义即可:
#define min(a, b) ((a) > (b)? (b) : (a))
#define max(a, b) ((a) > (b)? (a) : (b))
以上的min_t和max_t宏适需要提供数据类型,typeof的出现使这一步也可被省略。
include/linux/kernel.h
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; }) #define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
观察min和max的实现,它们通过typeof获取x和y的类型,然后定义局部变量以消除参数副作用。
思考问题:注意到中间的比较运算,
(void) (&_min1 == &_min2);
(void) (&_max1 == &_max2);
这两行代码是用来做类型检查的,如果x和y的类型不同,那么编译器将提示如下警告信息,这对检查代码很有帮助。
xxx.c:: warning: comparison of distinct pointer types lacks a cast
那么,类型检查是如何生效的呢?在stackoverflow上找到解释如下:
This provides for type checking, equality between pointers shall be between compatible types and gcc
will provide a warning for cases where this is not so.
We can see that equality between pointers requires that the pointers be of compatible types from the draft C99 standard section 6.5.9
Equality operators which says:
One of the following shall hold:
and includes:
both operands are pointers to qualified or unqualified versions of compatible types;
and we can find what a compatible type is from section 6.2.7
Compatible type and composite type which says:
Two types have compatible type if their types are the same
This discussion on osnews also covers this and it was inspired by the the GCC hacks in the Linux kernel article which has the same code sample. The answer says:
has to do with typechecking.
Making a simple program:
int x = 10;
long y = 20;
long r = min(x, y);Gives the following warning: warning: comparison of distinct pointer types lacks a cast
stackoverflow对此问题的讨论已经很清楚,简单的来说,c99标准约定,对于比较运算符 == 和 != 来说,如果比较的对象是指针,那么指针所指的对象类型必须一致,否则抛出上面的warning信息.
参考资料:http://stackoverflow.com/questions/5595593/min-macro-in-kernel-h
linux tricks 之 typeof用法.的更多相关文章
- Linux中find常见用法
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...
- Linux关于watch的用法
Linux关于watch的用法 2011-07-20 0个评论 收藏 我要投稿 watch 是一个非常实用的命令,基本所有的 Linux 发行版都带有这个小工具,如同名字一 ...
- [转]Linux中find常见用法示例
Linux中find常见用法示例[转]·find path -option [ -print ] [ -exec -ok command ] {} \;find命令的参 ...
- Linux下find命令用法详解
Linux下find命令用法详解 学神VIP烟火 学神IT教育:XueGod-IT 最负责任的线上直播教育平台 本文作者为VIP学员 烟火 第一部分:根据文件名查找 1.在当前目录 ...
- linux中make的用法
一.linux中make的用法 目的: 基本掌握了make 的用法,能在Linux系统上编程.环境: Linux系统准备: 准备三个文件:file1.c, file ...
- Linux中“!"的神奇用法
前言 实际上,不起眼的“!”在linux中有着很多让你惊叹的妙用.本文就来细数那些“!”的神奇用法. 执行上一条命令 例如,在执行完上面一条命令后,可以使用下面的方式再次执行上一条命令: $ wher ...
- Linux中sed的用法实践
Linux中sed的用法实践 参考资料:https://www.cnblogs.com/emanlee/archive/2013/09/07/3307642.html http://www.fn139 ...
- Linux中Sed的用法
Linux中Sed的用法 sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为: ...
- Linux tar命令高级用法——备份数据
Linux tar命令高级用法——备份数据 2015-12-31 Linux学习 Linux上有功能强大的tar命令,tar最初是为了制作磁带备份(tape archive)而设计的,它的作用是把文件 ...
随机推荐
- JavaScript的apply和call方法及其区别
参考资料: http://blog.csdn.net/myhahaxiao/article/details/6952321 apply和call能“劫持”其他对象的方法来执行,其形参如下: apply ...
- ios 判断控制器是否是第一次进入画页的做法
什么是第一次进入画页,只viewDidLoad一次: 所以只需要在viewDidLoad中加一个标识就行了. 加一个成员变量,或者属性,用来记录这个标识 一旦viewDidLoad后,这个就说明不是第 ...
- SSL协议运行机制
SSL/TLS协议运行机制 一.作用 不使用SSL/TLS的HTTP通信,就是不加密的通信.所有信息明文传播,带来了三大风险. (1) 窃听风险(eavesdropping):第三方可以获知通信内容. ...
- Centos更换yum库镜像
首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-B ...
- Vim常用操作(1)-常用指令
1.清空文件内容 Normal模式下,先输入"gg",将光标定位到文件首,然后输入"dG",文件就被清空了.当然也可以直接输入"ggdG".
- QQ 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件
QQ 编辑 腾讯QQ(简称“QQ”)是腾讯公司开发的一款基于Internet的即时通信(IM)软件.腾讯QQ支持在线聊天.视频通话.点对点断点续传文件.共享文件.网络硬盘.自定义面板.QQ邮箱等多种功 ...
- artEditor增加h5拍照上传图片
摘要: artEditor富文本 编辑器增加了图片拍照功能,点击图片按钮你可以从手机相册选择图片,也可以通过相机拍照上传. 项目地址:https://github.com/baixuexiyang/a ...
- 快还要更快,让PHP 7 运行更加神速
导读 PHP 7 比5.x 快上很多,即使只有单纯的版本升级就已经很有感,不过大家还是希望它变得越来越快,这时再做些小调整就会更有fu,Let's try it! 事前准备 说到PHP 7,那一定跑不 ...
- Unbuntu 下编译安装 PHP 必要库的安装
2010/08/22 LINUX, PHP 2 COMMENTS 编译环境 sudo apt-get install build-essential xml sudo apt-get install ...
- HDOJ 1106
#include<iostream> #include<algorithm> #include<string.h> #include<stdlib.h> ...