详解内核常用的两个表达式

来源:互联网 发布:php 队列实现群发推送 编辑:程序博客网 时间:2024/04/28 00:19

1、通过typeof来获得类型信息

      获取一个表达式类型信息的另一种方法是使用typeof。使用这个关键字的语法和sizeof的十分类似,但在语义上类似于用typedef定义的类型名结构。
      有两种方式来书写typeof的参数:使用一个表达式或者使用一个类型。下面的例子是使用一个表达式的方式:
           typeof(x[0][1])
      这里假定x是一个指向函数的指针的数组,描述的类型是函数值。
      下面的例子是使用一个类型名作为参数:
           typeof(int *)
       这里描述的类型是int类型的指针。
       当你想在为一个ISO C语言的程序编写一个头文件,那么就必须使用__typeof__来代替typeof。可以查看有关侯选关键字的信息。
       一个typeof结构可以在任意
能使用typedef的地方使用。例如:你可以在一个声明,一个类型转换,或者是在sizeof或typeof中使用。
      当typeof运算和表达式内
部特性结合起来使用时会显得特别有用。下面是如何用来定义一个安全的“最大”的宏,可以操作任何算术类型和并且对每一个参数仅仅求一次值:     

   #define max(a,b) \       ({ typeof (a) _a = (a); \           typeof (b) _b = (b); \         _a > _b ? _a : _b; })
       内部变量使用下划线开头是为了避免和内部使用的取名a和b的变量名发生冲突。实际上我们一直希望设计一种新的声明语法,允许你定义仅在初始化之后才有效的变量;这对于解决冲突更加行之有效。
       下面是更多的使用typeof的示例:
   *定义y的类型为x指向的类型:
        typeof (*x) y;
   *定义y为一个类型与x指向相同的数组
        typeof (*x) y[4];
   *定义y为字符指针数组类型
        typeof (typeof(char *)[4]) y;
         它等同于下面传统C声明:
      char *y[4];
    为了理解使用typeof的声明,并且理解为什么它是一种比较有效的写法,我们使用下面的宏定义来重写它:
      #define pointer(T)typeof(T *)
      #define array(T, N)typeof(T [N])
       现在我们可以如下重写上面的声明:
          array (pointer (char), 4) y;
       此时,array (pointer (char), 4)就是一个包含四个字符指针的数组。

2、内核常用container_of

      container_of是内核常用的一个宏,我们首先来看看它的定义,在内核的include/linux/kernel.h头文件中:     

/** * container_of - cast a member of a structure out to the containing structure * @ptr:the pointer to the member. * @type:the type of the container struct this is embedded in. * @member:the name of the member within the struct. * */#define container_of(ptr, type, member) ({\const typeof( ((type *)0)->member ) *__mptr = (ptr);\(type *)( (char *)__mptr - offsetof(type,member) );})
       首先说一下这个宏的作用:通过结构体成员的指针找到对应结构体的指针。有三个参数:第一个是结构体成员的指针,第二个是结构体的类型,第三个是结构体成员的类型。

       举例说明:我们之前实现了一个简单的字符设备驱动程序,在里面我们定义了一个字符设备:

   

/******定义自己的字符设备******/struct char_mem_t {    struct cdev memdev;    int device[MEMSIZE];}char_mem;

    我们首先定义结构体指针:

               struct char_mem_t *char_mem_p;

        那么,我们可以如下找到指向char_mem的指针:

               char_mem_p = container_of(&char_mem.memdev, struct char_mem_t,memdev);

        知道它能实现的功能了,接下来我们主要来看看它是如何实现这种功能的:

        主要思想就是建立一个临时变量,通过const typeof( ((type *)0)->member ) *__mptr = (ptr); 指向已知的那个结构体成员,这一点看看上面有关typeof的内容就知道了!

        接下来就是第二行代码了:(type *)( (char *)__mptr - offsetof(type,member) ); 其实就是通过指针的加减运算进行的,相信有C语言基础的都了解,例如有长度为5的以为整型数组int temp[5],有一个整型指针指向第三个数组元素,那么指针值减去4字节(假设此机器上整型长度为4字节),此时指针就指向了第二个元素,而不是第三个了。这是一样的道理,后面的offset就是计算该结构体成员在整个结构体中的偏移量。

        经过这两步走之后就能实现最终的功能了,接下来,再来看看offset()的实现。在include/linux/stddef.h头文件中  

#ifdef __compiler_offsetof#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)#else#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)#endif
          关于这部分的内容大家可以参考了一下网友的博文!

tanglinux的Linux内核中的常用宏container_of其实很简单,比较详细而且举了很多例子,这里我就不再写了。

原创粉丝点击