typeof是gcc的扩展功能,比较简单,是用来取得参数类型,具体可参考gcc官网的解释.

https://gcc.gnu.org/onlinedocs/gcc/Typeof.html

-------------------------------------------
本文系作者原创, 欢迎大家转载!
转载请注明出处:netwalker.blog.chinaunix.net
-------------------------------------------

由于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:

and includes:

and we can find what a compatible type is from section 6.2.7 Compatible type and composite type which says:

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:

stackoverflow对此问题的讨论已经很清楚,简单的来说,c99标准约定,对于比较运算符  == 和 != 来说,如果比较的对象是指针,那么指针所指的对象类型必须一致,否则抛出上面的warning信息.

参考资料:http://stackoverflow.com/questions/5595593/min-macro-in-kernel-h

05-11 14:01