C语言中的结构体的内存对齐,也叫做字节对齐 问题 分析

本文详细解释了C语言中结构体内存对齐的规则,包括默认对齐数、嵌套结构体对齐等,并指出Windows和Linux之间的对齐差异可能导致文件读取问题。提供了解决方案,使用`#parampack`来统一对齐方式。

一。C语言结构体中的内存对齐如何计算

规则一:第一个成员在结构体变量偏移量为0的地址处

规则二: 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

           对齐数 =编译器默认对齐数 与 该成员大小  比较后 取较小值

           默认对齐数:Linux中4字节,VS中8字节;

规则三 :结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍

规则四:如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

typedef struct Student {
    char sex;  占用1个字节                第1字节
    char sex1;  按照规则2,该成员占用1个字节 < vs中的8个字节,因此对齐数为1,,对齐到1的整倍数的字节处,即第二个字节。   第 2字节
    char sex2;  // 按照规则2,该成员占用1个字节 < vs中的8个字节,因此对齐数为1,,对齐到1的整倍数的字节处,即第三个字节。   第 3字节

//第4个字节没有用,空闲
    int age ;  // 按照规则2,该成员占用4个字节 < vs中的8个字节,因此对齐数为4,,对齐到4的整倍数 第五个字节。                           第5-8字节
    char name[6] ;//该成员是字符数组,要一个一个的看,数组中的每一个成员都是char,占用1个字节,小于 vs中的8个字节,对齐数为1,占用 9 - 14个字节

//第15,16 字节没有用,空闲
    int age2;        //        // 按照规则2,该成员占用4个字节 < vs中的8个字节,因此对齐数为4,,对齐到4的整倍数     ,1-14已经用了,就只能对齐到17了。占用17-20字节
    char name2[3];//3         //该成员是字符数组,要一个一个的看,数组中的每一个成员都是char,占用1个字节,小于 vs中的8个字节,对齐数为1,占用 21 - 23个字节

//第24 字节没有用,空闲
    char * address;//8        占用8,=  vs中的8个字节,因此对齐数为8,25-32个字节。
    //总和为:4+4+8+4+4+8 = 32字节
}_Student;

typedef struct Student {
	char sex;//占用1个字节                第1字节
	char sex1;//按照规则2,该成员占用1个字节 < vs中的8个字节,因此对齐数为1,,对齐到1的整倍数的字节处,即第二个字节。   第 2字节
	char sex2;// 按照规则2,该成员占用1个字节 < vs中的8个字节,因此对齐数为1,,对齐到1的整倍数的字节处,即第三个字节。   第 3字节

	//第4个字节没有用,空闲
	int age;//按照规则2,该成员占用4个字节 < vs中的8个字节,因此对齐数为4,,对齐到4的整倍数 第五个字节。                           第5-8字节
	char name[6];//该成员是字符数组,要一个一个的看,数组中的每一个成员都是char,占用1个字节,小于 vs中的8个字节,对齐数为1,占用 9 - 14个字节

//第15,16 字节没有用,空闲
	int age2; // 按照规则2,该成员占用4个字节 < vs中的8个字节,因此对齐数为4,,对齐到4的整倍数     ,1-14已经用了,就只能对齐到17了。占用17-20字节
	char name2[3];//该成员是字符数组,要一个一个的看,数组中的每一个成员都是char,占用1个字节,小于 vs中的8个字节,对齐数为1,占用 21 - 23个字节

//第24 字节没有用,空闲
	char * address;//8        占用8,=  vs中的8个字节,因此对齐数为8,25-32个字节。
	//总和为:4+4+8+4+4+8 = 32字节
}_Student;



void main() {
	_Student s;
	int result = sizeof(_Student);
	printf("result = %d\n", result);// 32

	//offsetof 宏可以使用 offsetof 宏计算一个结构体成员的偏移量。

	printf("%zd\n", offsetof(_Student, sex));  // 0
	printf("%zd\n", offsetof(_Student, sex1));  // 1
	printf("%zd\n", offsetof(_Student, sex2));  //2
	printf("%zd\n", offsetof(_Student, age));  // 4
	printf("%zd\n", offsetof(_Student, name));  // 8
	printf("%zd\n", offsetof(_Student, age2));  // 16
	printf("%zd\n", offsetof(_Student, name2));  // 20
	printf("%zd\n", offsetof(_Student, address));  // 24

	printf("断点在这里");
}

二,带来的问题以及如何fix

从上面看到:在windows vs上,内存对齐的标准是8.

在linux 上,内存对齐的标准是4.

这会有一个问题,当我们在windows使用文件写的方式,写入了一个二进制文件(假设叫做config.bin)。需要在linux 上读取,这就有问题了。写入的时候struct占用了80个字节,但是读取的时候就不一定这个struct就占用80个字节了。

解决方案:如有这样的需求(在windows上生成的文件,需要在linux 上读取)

建议我们在给这个struct前面加上

#param pack(1) //这表示当前使用1字节对齐的方式,既然使用了1字节对齐,就不存在8字节,4字节的问题了


typedef struct student{
char sex;
int age;
char name[64];

}

#param pack() //结束标记,表示只是如上的代码 使用1 字节对齐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值