c语言单元测试 kernel,GCC typeof在kernel中的使用——C语言的“编译时多态”

大家都知道,C语言本身没有多态的概念,函数没有重载的概念。然而随着C语言编写的软件逐渐庞大,越来越多地需要引入一些其他语言中的特性,来帮助更高效地进行开发,Linux

kernel是一个典型例子。

在动态类型的语言里面,往往有typeof这种语法,来获取变量的数据类型,比如JavaScript当中,typeof以字符串型式返回了这个变量的数据类型,借由这种特性,往往可以根据传入参数的类型不同,产生不同的行为。

GCC提供的typeof,实际上是在预编译时处理的,最后实际转化为数据类型被编译器处理。用法上也和上述语言不太一样。

基本用法是这样的:

1

2

3

int a;

typeof(a)

b;//这等同于int

b;

typeof(&a)

c;//这等同于int*

c;

那么在内核中这种特性是怎样使用的呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#define

typecheck(type,x) \

({ type __dummy; \

typeof(x)

__dummy2; \

(void)(&__dummy

== &__dummy2); \

1;

\

})

#define

typecheck_fn(type,function) \

({ typeof(type) __tmp = function; \

(void)__tmp;

\

})

这两段代码来自于include/linux/typecheck.h,用于数据类型检查。

宏typecheck用于检查x是否是type类型,如果不是,那么编译器会抛出一个warning(warning: comparison

of distinct pointer types lacks a

cast);而typecheck_fn则用于检查函数function是否是type类型,不一致则抛出warning(warning:

initialization from incompatible pointer type)。

原理很简单,对于typecheck,只有当x的类型与value一致,&__dummy ==

&__dummy2的比较才不会因为类型不匹配而抛出warning,详情可以参考C语言对于指针操作的标准规定。对于typecheck_fn,当然也只有function的返回值和参数表与type描述一致,才不会因为类型不匹配而抛出warning。

到这里有人可能会有一个疑问,内核代码里执行类型检查会不会降低效率?答案是不会的,因为实际上,这些为类型检查而声明的临时变量,实际上在上下文中都没有使用,并且还特别地强制类型转换为void防止任何由这些临时变量产生的结果被使用的情况,因此在编译器优化时,就将这些无用的代码删除了。

然后kernel中还定义了使用另一种类型检查策略的获取最大最小值的宏。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#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; })

这个例子里面不要求x和y是严格等于type类型,只要x和y能够安全地完成隐式类型转换为type就可以安全通过编译,否则会抛出warning。

另外一个非常经典的例子就是交换变量。

1

2

3

4

5

#define swap(a,

b) \

do {

typeof(a) __tmp = (a); (a) = (b); (b) = __tmp;

}while (0)

试想如果没有typeof,要怎么在C语言中实现这种类似C++模板的特性呢?

最后不得不提的就是container_of宏,在kernel中也被广泛使用。

1

2

3

4

5

6

7

8

9

10

#define

container_of(ptr, type, member)

({ \

const typeof(

((type *)0)->member ) *__mptr = (ptr); \

(type

*)( (char *)__mptr

- offsetof(type,member) );})

比如内核的task_struct数据结构中有一个member是sched_entity类型的se,这个member常常被调度器使用来决定进程的调度顺序,那么如果要根据这个se来获取包含它的task_struct,就可以使用container_of(p,

task_struct,

se)来实现(假设p是指向这个sched_entity的指针)。原理是先产生一个指针指向member,然后将这个指针减去member在这个struct中的偏移量,指针自然就指向了包含该member的对象了(这个地方用到了offsetof,含义一看便知,我就不再细说了)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值