项目场景:
本板解析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