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

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
          关于这部分的内容大家可以参考了一下网友的博文!

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值