gnu c标准中typeof关键字

来源:互联网 发布:知乎年薪百万是什么梗 编辑:程序博客网 时间:2024/06/05 11:12

c++11中decltype 操作符作用是自动推导表达式的数据类型,以解决泛型编程中有些类型由模板参数决定而难以(甚至不可能)表示的问题。
typeof(ps: 不是 typedef)与decltype类似:能够自动推导表达式类型

typeof()参数可以是:表达式/类型
1>表达式:typeof(x[0](1))

  • x是函数指针数组,上面可得到函数返回值类型
  • 表达式不会执行

extern int foo();
typeof(foo()) var; //声明一个int型变量

2>类型:
typeof(int *) a,b;
等价于:int *a,*b;

typeof(int) a; /int类型/
typeof(‘b’) a;
/* gcc中’b’自动提升为int, 注意typeof(char)和typeof(‘b’)结果不一样,用sizeof可以看出来*/

others:
把y定义成x指向的数据类型:typeof(*x) y;
把y定义成x指向数据类型的数组:typeof(*x) y[4];
把y定义成一个字符指针数组:typeof(typeof(char *)[4]) y; == char *y[4];

另一种定义方式:
#define pointer(T) typeof(T *)
#define array(T,N) typeof(T [N])
array (pointer(char),4) y;

把T定义成一个表达式的类型:typedef typeof(expr) T;

typeof(int *) p1,p2; == int *p1, *p2;
typeof(int) *p3,p4; == int *p3, p4;
typeof(int [10]) a1, a2; == int a1[10], a2[10];

注意 :
typeof构造中的类型名
不能包含存储类说明符,如extern或static。
允许包含类型限定符,如const或volatile。
typeof(extern int) a; //无效

extern typeof(int) b; //用外部链接来声明标识符b是有效的
typeof(char * const) p = “a”; //声明一个使用const限定的char指针,表示指针p不能被修改

在宏声明中使用typeof
typeof主要用在宏定义中。可用typeof关键字来引用宏参数的类型。因此,
在宏实参的类型不明确的情况下,可以构造不确定类型的对象。
下面是交换两个变量值的宏定义:
#define SWAP(a,b) {\
typeof(a) _t=a;\
a=b;\
b=_t;}
可交换所有基本数据类型的变量(整数/字符/结构等)

  • typeof是gnu c标准的扩展,标准的iso c没有这个关键字,所以编译时不能加任何iso c标准选项,否则会报错,比如-std=c90,编译器就会有提示一堆error,而-std=gnu90可以
  • 一般情况下用typeof就可以,但如果要兼容iso c,最好用__typeof__
  • 只要能用typedef的地方就可用typeof

函数指针:

int add(int param1, int param2) {
return param1 + param2;
}
int sub(int param1, int param2) {
return param1 - param2;
}
int mul(int param1, int param2) {
return param1 * param2;
}
int main() {
int (*func[3]) (int, int) = {add, sub, mul};
typeof(func[0](1, 1)) sum = 100;
typeof(func[1](1, 1)) dif = 101;
typeof(func[2](1, 1)) pro = 102;
printf(“sum:\t%d\n”, sum);
printf(“dif:\t%d\n”, dif);
printf(“pro:\t%d\n”, pro);
return 0;
}

int aa (int aaa) {
printf(” ### aa ### \n”);
return 0;
}
int main(int argc, char* argv[]) {
int (*(x[2])) (int);
x[0] = aa;
printf(” sizeof(typeof(x[0](1))):\t%d \n”,sizeof(typeof(x[0](1))) ); // 4 函数aa返回值类型
printf(” (typeof(x[0])):\t%d \n”,sizeof(typeof(x[0])) ); // 8 函数指针类型 64os
return 0;
}

宏定义:

#define pointer(T) typeof(T *)
#define array(T, N) typeof(T[N])
int main() {
array(pointer(char), 4) pchar = {“hello”, “world”, “good”, “night”};
for (int i = 0; i < 4; i++)
printf(“pchar[%d]:\t%s\n”, i, pchar[i]);
return 0;
}

实战:
/*
* 选自 linux-2.6.7 内核源码
* filename: linux-2.6.7/include/linux/kernel.h
*/
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })

  • typeof作用:让min接受任何类型的参数而不必局限于单一类型,有点泛型编程的味道
  • (void) (&_x == &_y); 完全是一句废话,因为不能保证两个实参类型相同,需要做检测,而c不支持typeof(_x) == typeof(_y)这样的操作,所以故意判断他们2个的地址指针是否相等,显然是不可能相等,但是如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,会抛出一个编译警告。也就是说char p; int *q; 然后p==q;,这个判断因为一个是char一个是int*,会在编译时产生一个warning。巧妙就巧妙在这里。
  • (void)是因为仅表达式 &_x == &_y 本身没意义,如果没有这个 (void) 编译器同样会警告:statement with no effect [-Wunused-value],无效的语句,如果不想看到这个警告,那就在前面加个 (void) 。
    int x;
    //float y;
    int y;
    &x == &y;
0 0