C语言结构体内存对齐和offsetof宏、container

您所在的位置:网站首页 c语言内存地址 C语言结构体内存对齐和offsetof宏、container

C语言结构体内存对齐和offsetof宏、container

2022-11-29 02:03| 来源: 网络整理| 查看: 265

1.结构体变量中的元素如何访问

(1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式);实质上都是指针方式访问。 (2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来访问。 (C语言规定用结构体变量来访问元素用. 用结构体变量的指针来访问元素用->。)

2.结构体的对齐访问

总结下:结构体对齐的分析要点和关键: 1、结构体对齐要考虑:结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数(编译器设置为4字节对齐时,如果编译器设置为8字节对齐,则这里的4是8) 2、结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。 3、编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。

gcc支持但不推荐的对齐指令:#pragma pack() #pragma pack(n) (n=1/2/4/8)

我们需要#prgama pack(n)开头,以#pragma pack()结尾,定义一个区间,这个区间内的对齐参数就是n。

#pragma pack(1) struct mystruct { short d; int b; char a; }; #pragma pack() gcc推荐的对齐指令__attribute__((packed)) attribute((aligned(n)))

(1) __attribute__((packed))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。packed的作用就是取消对齐访问。

struct mystruct { short d; int b; char a; }__attribute__((packed));

(2)__attribute__((aligned(n)))使用时直接放在要进行内存对齐的类型定义的后面,然后它起作用的范围只有加了这个东西的这一个类型。它的作用是让整个结构体变量整体进行n字节对齐(注意是结构体变量整体n字节对齐,而不是结构体内各元素也要n字节对齐)

struct mystruct { short d; int b; char a; }__attribute__((aligned(16)));

参考阅读blog: 结构体字节对齐参考博客

GCC___attribute__关键字和字节对齐

3.offsetof宏

(1)offsetof宏的作用是:用宏来计算结构体中某个元素和结构体首地址的偏移量(其实质是通过编译器来帮我们计算)。 (2)offsetof宏的原理:我们虚拟一个type类型结构体变量,然后用type.member的方式来访问那个member元素,继而得到member相对于整个变量首地址的偏移量。

// TYPE是结构体类型,MEMBER是结构体中一个元素的元素名 // 这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int #define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)

(TYPE *)0这是一个强制类型转换,把0地址强制类型转换成一个指针,这个指针指向一个TYPE类型的结构体变量。 (实际上这个结构体变量可能不存在,但是只要我不去解引用这个指针就不会出错)。 ((TYPE *)0)->MEMBER (TYPE *)0是一个TYPE类型结构体变量的指针,通过指针指针来访问这个结构体变量的member元素

&((TYPE *)0)->MEMBER 等效于&(((TYPE *)0)->MEMBER),意义就是得到member元素的地址。但是因为整个结构体变量的首地址是0,

4.container_of宏 // TYPE是结构体类型,MEMBER是结构体中一个元素的元素名 // 这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int #define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) // ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名 // 这个宏返回的就是指向整个结构体变量的指针,类型是(type *) #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); })

(1)作用:知道一个结构体中某个元素的指针,反推这个结构体变量的指针。有了container_of宏,我们可以从一个元素的指针得到整个结构体变量的指针,继而得到结构体中其他元素的指针。 (2)typeof关键字的作用是:typepef(a)时由变量a得到a的类型,typeof就是由变量名得到变量数据类型的。 (3)这个宏的工作原理:先用typeof得到member元素的类型定义成一个指针,然后用这个指针减去该元素相对于整个结构体变量的偏移量(偏移量用offsetof宏得到的),减去之后得到的就是整个结构体变量的首地址了,再把这个地址强制类型转换为type *即可。

struct mystruct { short d; int b; char a; }; int main(void) { struct mystruct s1; struct mystruct *ps = NULL; int *p = &(s1.a); printf("s1 = %p.\n", &s1); ps = container_of(p, struct mystruct, a); printf("ps = %p.\n", ps); return 0; }

知道一个结构体中a元素的指针,反推这个结构体变量的指针。 结果为: s1 = 0x7ffd8cd5d2fc. ps = 0x7ffd8cd5d2fc.



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3