offsetof ,container_of ,typeof 用法

一、offsetof 概述

	宏, 定义在头文件 #include <stddef.h>
offsetof  :
        Retrieves the offset of a member from the beginning of its parent structure.
	size_t offsetof(structName, memberName);
Parameters:
    	 structName : Name of the parent data structure.
         memberName :Name of the member in the parent data structure for which to determine the offset.
Return Value : 
	 offsetof returns the offset in bytes of the specified member from 
         the beginning of its parent data structure. It is undefined for bit fields.
Remarks :
         The offsetof macro returns the offset in bytes of memberName from the beginning of the structure specified by structName. 	 You can specify types with the struct keyword.
Note  :
    	offsetof is not a function and cannot be described using a C prototype.
	#define offsetof(s, m)   (size_t)&(((s *)0)->m) 

s是一个结构名,它有一个名为m的成员(s和m 是宏offsetof的形参,它实际是返回结构s的成员m的偏移地址.

(s *)0 是骗编译器说有一个指向类(或结构)s的指针,其地址值0 

&((s *)0)->m   是要取得类s中成员变量m的地址. 因基址为0,这时m的地址当然就是m在s中的偏移

最后转换size_t 型,即unsigned int。

二、Demo-test

#include <stdio.h>
typedef struct _Node
{
	char a;
	int b;
}Node;

int main()
{

  unsigned   int res = 0;
  res = offsetof(Node, b);
  printf("res=%d\n",  res);
}
结果 res = 4 由此可见 在内存中有了补齐 ,按照4给字节对齐

三、container_of 

container_of 的定义在 linux 内核 include/linux/kernel.h 中

[cpp]  view plain  copy
  1. /** 
  2.  * container_of - cast a member of a structure out to the containing structure 
  3.  * @ptr:        the pointer to the member. 
  4.  * @type:       the type of the container struct this is embedded in. 
  5.  * @member:     the name of the member within the struct. 
  6.  * 
  7.  */  
  8. #define container_of(ptr, type, member) ({                      \  
  9.         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \  
  10.         (type *)( (char *)__mptr - offsetof(type,member) );})  

其中的offsetof 的定义在 include/linux/stddef.h

[cpp]  view plain  copy
  1. #ifdef __compiler_offsetof  
  2. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
  3. #else  
  4. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  5. #endif  

在使用过程中一般不会有什么 问题,如:

[cpp]  view plain  copy
  1. typedef struct frame {  
  2.         int a;  
  3.         char b;  
  4.         char name[10];  
  5. } frame_t;  
  6.   
  7. int main(int argc, char **argv)  
  8. {  
  9.         frame_t fra, *pf;  
  10.         fra.a = 1;  
  11.         fra.b = 2;  
  12.         snprintf(fra.name, 5, "cjz%d", 1);  
  13.   
  14.         pf = container_of(&fra.a, frame_t, a);  
  15.         printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);  
  16.   
  17.         return 0;  
  18. }  

但是下边的编译的时候就会有warning

[cpp]  view plain  copy
  1. typedef struct frame {  
  2.         int a;  
  3.         char b;  
  4.         char name[10];  
  5. } frame_t;  
  6.   
  7. int main(int argc, char **argv)  
  8. {  
  9.         frame_t fra, *pf;  
  10.         fra.a = 1;  
  11.         fra.b = 2;  
  12.         snprintf(fra.name, 5, "cjz%d", 1);  
  13.   
  14.         pf = container_of(fra.name, frame_t, name);  
  15.         printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);  
  16.   
  17.         return 0;  
  18. }  
编译过程:

[cpp]  view plain  copy
  1. gcc    -c -o main.o main.c  
  2. main.c: In function ‘main’:  
  3. main.c:29:57: warning: initialization from incompatible pointer type [enabled by default]  
  4. gcc -Wall  -I./ -o test main.o  


注意红色部分,这是怎么回事呢?下面我们就来分析一下

container_of的部分展开


[cpp]  view plain  copy
  1. container_of(fra.name, frame_t, name) 展开如下  
  2.   
  3.  ({const typeof( ((frame_t *)0)->name ) *__mptr = (fra.name);    \  
  4.    (frame_t *)( (char *)__mptr - offsetof(frame_t, name) );})  
  5.   
  6.   
  7. 这样看来好像也没有什么 问题啊,但为什么 会有警告呢?  
  8.   
  9. 因为typeof(数组名) ,这个我个先把它称为数组名类型,而typeof( ) 中要的是一个C中定义的类型,应该为数组元素类型,所以我们这里应该传数组首元素。  
  10.   
  11. pf = container_of(fra.name, frame_t, name[0]);  
  12.   
  13. 注意红色部分与之前的不同,之前是name, 而这里是name[0]  
  14.   
  15. 改后再编译  
  16.   
  17. gcc    -c -o main.o main.c  
  18. gcc -Wall  -I./ -o test main.o  
  19.   
  20. 警告就没有了  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tiny丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值