最近发现两个非常牛的宏:
一个是计算某个结构体成员的偏移量,
一个是计算一个结构体的首地址
这两个宏在Linux kernel里非常基础,非常常用,
今天抽闲暇时间好好调试了一番。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/**
* 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)); })
其中,typeof的使用类似于sizeof的使用,
typeof返回一个数据类型,sizeof返回一个数据结构的大小(byte),
////gcc version
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
1、宏offsetof的例子(来自man offsetof)
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
struct s {
int i;
char c;
double d;
char a[];
};
/* Output is compiler dependent */
printf("offsets: i=%ld; c=%ld; d=%ld a=%ld\n",
(long) offsetof(struct s, i),
(long) offsetof(struct s, c),
(long) offsetof(struct s, d),
(long) offsetof(struct s, a));
printf("sizeof(struct s)=%ld\n", (long) sizeof(struct s));
exit(EXIT_SUCCESS);
}
//output
offsets: i=0; c=4; d=8 a=16
sizeof(struct s)=16
【分析】
2、宏container_of的例子
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
int main(void)
{
struct s {
int i;
char c;
double d;
char a[];
};
struct s m_s, *p_m_s;
double *p_d = &m_s.d;
printf("0x%.8x\n",&m_s);
printf(" 0x%.8x \n 0x%.8x \n 0x%.8x \n 0x%.8x \n",&m_s.i,&m_s.c,&m_s.d,m_s.a);
//p_m_s = container_of(p_d, struct s, d);
printf("--0x%x\n",container_of(p_d, struct s, d));
exit(EXIT_SUCCESS);
}
////output
0xb39e8290
0xb39e8290
0xb39e8294
0xb39e8298
0xb39e82a0
--0xb39e8290
其中有三个地址是一样的,也就是结构体的首地址。
【分析】
另外,最近老在想sizeof到底是如果实现的?