C语言结构体对齐

时间:2024-12-11 21:37:02

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

(1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式);实质上都是指针方式访问。
(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来访问。(.和->访问结构体元素其实质是一样的,只是C语言规定用结构体变量来访问元素用. 用结构体变量的指针来访问元素用->。实际上在高级语言中已经不区分了,都用.)
(3)结构体的访问方式有点类似于数组下标的方式

2.利用指针访问结构体元素

  结构体元素地址=结构体首地址+元素偏移量

  

struct mystruct
{
int a;
int b; } s1; //s1.b的地址
int* p=(int*)((int)&s1+);
*p=;// s1.b=5;

3.结构体对齐

  一般情况下,为了配合硬件,如果对齐排布和访问会提高效率,否则会大大降低效率。

  (0)、一般编辑器默认4字节对齐。

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

struct mystruct1
{    // 1字节对齐 4字节对齐
int a;         // 4 4
char b; // 1 2(1+1)
short c;   // 2 2
}; struct mystruct11
{ // 1字节对齐 4字节对齐
int a; // 4 4
char b; // 1 2(1+1)
short c;   // 2 2
}; typedef struct mystruct111
{ // 1字节对齐 4字节对齐 2字节对齐
int a; // 4 4 4
char b; // 1 2(1+1) 2
short c; // 2 2 2
short d; // 2 4(2+2) 2
} My111; typedef struct mystruct2
{ // 1字节对齐 4字节对齐
char a; // 1 4(1+3)
int b; // 4 4
short c;  // 2 4(2+2)
}MyS2; struct mystruct21
{ // 1字节对齐 4字节对齐
char a; // 1 4(1+3)
int b; // 4 4
short c; // 2 4(2+2)
} ;
typedef struct myStruct5
{ // 1字节对齐 4字节对齐
int a; // 4 4
struct mystruct1 s1; // 7 8
double b; // 8 8
int c; // 4 4
}MyS5; struct stu
{ // 1字节对齐 4字节对齐
char sex; // 1 4(1+3)
int length; // 4 4
char name[]; // 10 12(10+2)
};

4.结构体对齐指令

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

#pragma pack(2)

struct s
{
char c; //2 (1+1)
int b; //4 (4) } ;
#pragma pack()

  取消对齐访问
  __attribute__((packed));
  设置结构体整体对齐访问(不包含元素)
  __attribute__((aligned(n)));

  

struct mystruct11
{ // 1字节对齐 4字节对齐
int a; // 4 4
char b; // 1 2(1+1)
short c; // 2 2
}__attribute__((packed)); typedef struct mystruct111
{ // 1字节对齐 4字节对齐 2字节对齐
int a; // 4 4 4
char b; // 1 2(1+1) 2
short c; // 2 2 2
short d; // 2 4(2+2) 2
}__attribute__((aligned())) My111;

5.offsetof宏与container_of宏

offsetof            在0地址处虚拟出一个结构体,通过元素的地址则为偏移量

container_of     通过元素地址减去偏移量得到结构体地址

typeof()传入变量,返回相应的数据类型。
#include<stdio.h>

struct mystruct
{
char a;
int b;
short c; };
// TYPE是结构体类型,MEMBER是结构体中一个元素的元素名
// 这个宏返回的是member元素相对于整个结构体变量的首地址的偏移量,类型是int
#define offsetof(TYPE, MEMBER) ((int) &(((TYPE *)0)->MEMBER))//TYPE *为传入值 // ptr是指向结构体元素member的指针,type是结构体类型,member是结构体中一个元素的元素名
// 这个宏返回的就是指向整个结构体变量的指针,类型是(type *)
//typeof() 是通过变量名 返回数据类型的
#define container_of(ptr, type, member) ({ \
const typeof(((type *))->member) * __mptr = (ptr); \ //定义一个typeof(((type *)0)->member)类型的指针指向 结构体元素地址
(type *)((char *)__mptr - offsetof(type, member)); }) //元素地址-偏移量=结构体首地址
//通过元素地址减去偏移量得到结构体地址
int main()
{
struct mystruct s1;
struct mystruct *Ps;
s1.b=;
int * pb=&s1.b;
Ps=container_of(pb,struct mystruct,b);
printf("container_of宏实例\n");
printf("&s1=%p\n",&s1);
printf("Ps=%p\n",Ps); //int *p=(int *)((char*)&s1+4);
int *p=(int *)((int)&s1+);
printf("*p=%d.\n",*p);
printf("offsetof宏实例\n");
int offsetof_a=offsetof(struct mystruct,a);
int offsetof_b=offsetof(struct mystruct,b);
int offsetof_c=offsetof(struct mystruct,c);
printf("offsetof_a=%d\n",offsetof_a);
printf("offsetof_b=%d\n",offsetof_b);
printf("offsetof_c=%d\n",offsetof_c); return ; }