内存对齐和字节对齐问题

项目场景:

本板解析bit完成后通过udp上报bit给对方。


问题描述

前几天在调试网络bit上报的时候出现对方接收内容与协议约定有错位的情况。当时在定义报文内容时就有问题,没有考虑到内存对齐的问题,后来在开发的时候又匆匆忙忙的没有仔细考虑,直接就按照格式写结构体了。


原因分析:

本板发送报文采用的是结构体,对方是申请了一个数组,将收到的内容存到数组内,对方在内存上是连续的,因此对方在接收上应该不会出问题,发送的接口也是很成熟的东西。所以怀疑本板的发送结构体可能有内存不对齐的问题。代码没法上传,在自己电脑上演示一下。

在ubuntu64位上做实验:

代码如下:

#include<stdio.h>
#include<string.h>

#define		strucOffset(struc, member)	(size_t)&(((struc *)0)->member)

struct structA{
	
	unsigned char a;
	unsigned char b;
	unsigned int  c;
	unsigned long d;
	double e;
	struct testStruc *f;

}StructA;



int main(void)
{
	printf("sizeof(StructA):%ld\n",sizeof(StructA));
	int a = strucOffset(struct structA, f);
	printf("a is %d\n",a);
	return 0;
}

结构体内定义了不同的成员,32位的编译器应该是按照4字节对齐,而实验用的是ubuntu64位,因此是8字节对齐.按照这个规律上面这个大小应该是4+4+8+8+8 = 32;

编译看一下:

alientek@ubuntu16:~/c_linux/codetest$ gcc memAlien.c -o memAlien
alientek@ubuntu16:~/c_linux/codetest$ ./memAlien 
sizeof(StructA):32
a is 24

再写一个结构体看一下:

include<stdio.h>
#include<string.h>

#define		strucOffset(struc, member)	(size_t)&(((struc *)0)->member)

struct structA{
	
	unsigned char a[5];
	unsigned char b;
	unsigned int  c;
	unsigned short c1;
	unsigned long d;
	unsigned int d1;
	double e;
	struct testStruc *f;

}StructA;



int main(void)
{
	printf("sizeof(StructA):%ld\n",sizeof(StructA));
	int a = strucOffset(struct structA, f);
	printf("a is %d\n",a);
	return 0;
}

按8字节对齐的方式的话,应该是8+4+4+8+8+8+8=48;应该是48字节。

alientek@ubuntu16:~/c_linux/codetest$ gcc memAlien.c -o memAlien
alientek@ubuntu16:~/c_linux/codetest$ ./memAlien 
sizeof(StructA):48
a is 40

具体补齐的方式得把内存想成一个一个的对齐的表格就很好计算了。如果是4字节对齐那么一行就是四个字节,如果是8字节对齐,那么一行就是八个字节。

要注意的是不同的编译器下指针的大小是不一样的,32位的指针4字节,64位8字节。这个很好理解。

定义了一个宏用来计算成员相对结构体的偏移量。这个以后在项目中也可以使用。


解决方案:

如果结构体很大,里面的成员很多,那么就很麻烦了,牵一发动全身,信号编译器有办法解决。可以使用两种方法来解决对齐问题。

1.#pragma pack (n)  这个方法是让编译器强制按照n字节对齐,假设需要无缝凭借,那么直接就写成1就ok。

2.__attribute__((packed)) 这个是直接取消内存对齐,直接无缝拼接。测试一下。

#include<stdio.h>
#include<string.h>

#define		strucOffset(struc, member)	(size_t)&(((struc *)0)->member)

#pragma pack(1)
struct structA{
	
	unsigned char a[5];
	unsigned char b;
	unsigned int  c;
	unsigned short c1;
	unsigned long d;
	unsigned int d1;
	double e;
	struct testStruc *f;

}StructA;



int main(void)
{
	printf("sizeof(StructA):%ld\n",sizeof(StructA));
	int a = strucOffset(struct structA, f);
	printf("a is %d\n",a);
	return 0;
}
alientek@ubuntu16:~/c_linux/codetest$ gcc memAlien.c -o memAlien
alientek@ubuntu16:~/c_linux/codetest$ ./memAlien 
sizeof(StructA):40
a is 32
#include<stdio.h>
#include<string.h>

#define		strucOffset(struc, member)	(size_t)&(((struc *)0)->member)

//#pragma pack(1)
struct __attribute__((packed))  dddd{
	
	unsigned char a[5];
	unsigned char b;
	unsigned int  c;
	unsigned short c1;
	unsigned long d;
	unsigned int d1;
	double e;
	struct testStruc *f;

}StructA;



int main(void)
{
	printf("sizeof(StructA):%ld\n",sizeof(StructA));
	int a = strucOffset(struct dddd, f);
	printf("a is %d\n",a);
	return 0;
}
alientek@ubuntu16:~/c_linux/codetest$ gcc memAlien.c -o memAlien
alientek@ubuntu16:~/c_linux/codetest$ ./memAlien 
sizeof(StructA):40
a is 32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值