结构体字节对齐

1、CPU读取内存数据

         计算机的内存系统通常以为单位进行数据传输32位系统是4字节,64位系统是8字节。

  当数据存储在对齐的地址上时,数据的起始地址正好是内存块的边界,CPU可以一次性读取完整的数据。

(1)对齐数据的访问

    ①如果int变量存储在地址0x1000,那么CPU可以一次读取从 0x1000~0x1003 的4字节数据

    ②如果double变量存储在地址0x2000,那么CPU可以一次读取从 0x2000~0x2007 的8字节数据

(2)未对齐数据的访问

       ① 如果int变量存储在地址0x1001,那么CPU分两次读取:0x1001~0x1003  +  0x1004

       ② 如果double变量存储在地址0x2002,那么CPU分两次读取:0x2002~0x2007 + 0x2008~0x2009

        

2、内存对齐原则

(1)第一个成员偏移0,之后每个成员的起始位置是当前成员的整数倍;

(2)如果结构体A中含有结构体B,B的起始位置是B中最大元素大小整数倍;

(3)结构体总大小是内部最大成员的整数倍。

系统默认的字节对齐值:32位系统是4字节,64位系统是8字节。

 

3、示例代码1

#include <stdio.h>
#include <string.h>
#define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 )
struct employee
{
char *name;
int num;
short age;
char evaluation;
char *department;
};
int main()
{
PRINT_SIZE(sizeof(struct employee));
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, name));
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, num));
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, age));
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, evaluation));
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct employee, department));
return 0;
}

执行结果:

sizeof(struct employee) is 24
STRUCT_MEMBER_OFFSET(struct employee, name) is 0
STRUCT_MEMBER_OFFSET(struct employee, num) is 8
STRUCT_MEMBER_OFFSET(struct employee, age) is 12
STRUCT_MEMBER_OFFSET(struct employee, evaluation) is 14
STRUCT_MEMBER_OFFSET(struct employee, department) is 16

4、示例代码2

#include <stdio.h>
#include <string.h>
#define PRINT_SIZE(intValue) printf(#intValue" is %d\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 )
struct student
{
char name[10];
int num;
char sex;
};
int main()
{
PRINT_SIZE(sizeof(struct student))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, name))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, num))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct student, sex))
return 0;
}

执行结果

PS D:\Code\Data Structure> .\test.exe
sizeof(struct student) is 20
STRUCT_MEMBER_OFFSET(struct student, name) is 0
STRUCT_MEMBER_OFFSET(struct student, num) is 12
STRUCT_MEMBER_OFFSET(struct student, sex) is 16

 

5、两种字节对齐方式

(1)#pragma pack(n)  

    ① 指定structunion成员的对齐边界为 n 字节

    ② n的取值为2的幂数,1, 2, 4, 8, 16

    ③ 如果没有指定#pragma pack,编译器会根据目标平台的默认对齐值4字节或者8字节;

    ④ n默认对齐值较小值 进行对齐

#pragma pack(1)
struct Example
{
char a; // 1字节
int b; // 4字节
short c; // 2字节
};
#pragma pack()

n取1时,紧凑排列, Example结构体的大小=7 

#pragma pack(2)
struct Example
{
char a; // 1字节
int b; // 4字节
short c; // 2字节
};
#pragma pack()

 n取2时,Example结构体的大小=8 

 

(2)__attribute__( aligned(n) ) 

 编译器会将让n默认的对齐字节数进行比较,取较大值为对齐字节数

 

(3)__attribute__( (packed) ) 

取消结构在编译过程中的优化对齐, 等同于#pragma pack(1)  

 

#include <stdio.h>
#include <string.h>
#define PRINT_SIZE(intValue) printf(#intValue" is %ld\n",(intValue));
#define STRUCT_MEMBER_OFFSET(type, member) ( (char*) & ((type*)0)->member - (char*)0 )
typedef struct mystruct_packed
{
int a;
double b;
char c;
}__attribute__((packed)) AP;
typedef struct mystruct2
{
int a;
double b;
char c;
}__attribute__((aligned(2))) A2;
typedef struct mystruct4
{
int a;
double b;
char c;
}__attribute__((aligned(4))) A4;
typedef struct mystruct8
{
int a;
double b;
char c;
}__attribute__((aligned(8))) A8;
typedef struct mystruct16
{
int a;
double b;
char c;
}__attribute__((aligned(16))) A16;
typedef struct mystruct32
{
int a;
double b;
char c;
}__attribute__((aligned(32))) A32;
int main()
{
PRINT_SIZE(sizeof(struct mystruct_packed))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct_packed, c))
printf("\n");
PRINT_SIZE(sizeof(struct mystruct2))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct2, c))
printf("\n");
PRINT_SIZE(sizeof(struct mystruct4))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct4, c))
printf("\n");
PRINT_SIZE(sizeof(struct mystruct8))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct8, c))
printf("\n");
PRINT_SIZE(sizeof(struct mystruct16))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct16, c))
printf("\n");
PRINT_SIZE(sizeof(struct mystruct32))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, a))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, b))
PRINT_SIZE(STRUCT_MEMBER_OFFSET(struct mystruct32, c))
return 0;
}

 

执行结果:

xuanmiao@linux:~/Test$ ./test
sizeof(struct mystruct_packed) is 13
STRUCT_MEMBER_OFFSET(struct mystruct_packed, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct_packed, b) is 4
STRUCT_MEMBER_OFFSET(struct mystruct_packed, c) is 12
sizeof(struct mystruct2) is 24
STRUCT_MEMBER_OFFSET(struct mystruct2, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct2, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct2, c) is 16
sizeof(struct mystruct4) is 24
STRUCT_MEMBER_OFFSET(struct mystruct4, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct4, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct4, c) is 16
sizeof(struct mystruct8) is 24
STRUCT_MEMBER_OFFSET(struct mystruct8, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct8, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct8, c) is 16
sizeof(struct mystruct16) is 32
STRUCT_MEMBER_OFFSET(struct mystruct16, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct16, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct16, c) is 16
sizeof(struct mystruct32) is 32
STRUCT_MEMBER_OFFSET(struct mystruct32, a) is 0
STRUCT_MEMBER_OFFSET(struct mystruct32, b) is 8
STRUCT_MEMBER_OFFSET(struct mystruct32, c) is 16

 

posted @   轩~邈  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2022-02-25 字符串函数
点击右上角即可分享
微信分享提示