C语言获取变量类型的方法

前言

众所周知,C语言本身没有多态的概念,函数也没用重载的概念。
而在动态类型的语言里面,往往有typeof这种语法,来获取变量的数据类型。例如,JavaScript当中,typeof以字符串型式返回了这个变量的数据类型;python中有type()的方法来获取变量类型。借由这种特性,往往可以根据传入参数的类型不同,产生不同的行为。

C语言标准并不支持typeof的语法,但是gcc扩展是支持typeof语法的。
可以查看gcc对于typeof的说明

用法

1
2
3
int a;
typeof(a) b; //相当于 int b;
typeof(&a) c; //相当于int *c;

也可以直接使用类型作为参数:
typeof(int *)

用途

在linux源码中,typeof被用来实现一个安全的max和min宏定义。
include /linux/kernel.h中:

1
2
3
4
5
6
7
8
9
10
11
#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; })

可以看出,linux使用typeof获取传入的x和y的类型,然后定义局部变量以消除参数副作用。

注意中间的比较操作 (void) (&_max1 == &_max2)(void) (&_min1 == &_min2)
这两行代码是用来做类型检查的,如果x和y的类型不同,那么编译器将提示如下警告信息,这对检查代码很有帮助。
xxx.c:35: warning: comparison of distinct pointer types lacks a cast
这个类型检查是怎么回事呢?
简单来说,在C99标准的第6.5.9节中规定,对于比较运算符 == 和 != 来说,如果比较的对象是指针,那么指针所指的对象类型必须一致,否则抛出上面的warning信息.

GCC对Typeof的处理

GCC提供的typeof,实际上是在预编译时处理的,最后实际转化为数据类型被编译器处理。

参考链接
6.6 Referring to a Type with typeof
藝術與核心