整个过程大概是这样的:
甲方和乙方接口需要数据传输,比如 甲方AA传递到乙方BB,乙方想用甲方AA中的数据,由于某方后期修改了自己的定义,导致sizeof不统一,整个系统发生了崩盘,引发了一次严重的线上事故。
甲方AA:
代码语言:javascript复制typedef struct aa
{
int id;
char a[6];
enum day{
one,
two,
three =4,
four = 12
};
double w;
float h;
long g;
}AA;
乙方BB:
代码语言:javascript复制typedef struct bb
{
int id;
char a[3];
enum day{
one,
two,
three =4,
four = 100
};
double w;
float h;
long g;
}BB;
双方通信:
代码语言:javascript复制 AA aa = {1,"wxh",2.2,3.3,4321};
BB bb = *(BB*)(&aa);
cout<<sizeof(AA)<<" "<<sizeof(BB)<<" "<<aa.h<<" "<<bb.h<<endl;
memcpy(&bb,&aa,sizeof(aa));
cout<<sizeof(AA)<<" "<<sizeof(BB)<<" "<<aa.h<<" "<<bb.h<<endl;
结果:
40 32 3.3 -1.58819e-23 40 32 3.3 -1.58819e-23
#pragma pack(1) //1字节对齐
30 27 3.3 4.47049e-08 30 27 3.3 4.47049e-08
本来甲方传了一个 3.3,而乙方得到的确是越界的负值 ,引发了系统崩溃。
类型 | 32位 | 64位 |
---|---|---|
char | 1 | 1 |
int | 4 | 大多数4,少数8 |
short | 2 | 2 |
long | 4 | 8 |
float | 4 | 4 |
double | 8 | 8 |
指针 | 4 | 8 |
enum | 4 | 4 |
对齐原因:
1,性能问题:数据结构尽可能在自然边界上对齐,若访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存只要访问一次。
2,空间问题:没有进行内存对齐的结构体或类会浪费一定空间,当创建对象越多时,消耗的空间也越多。
3,平台问题:不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
对齐规则:
struct:
1,结构体变量中成员的便移量必须是成员大小的整数倍数;
2,结构体大小必须是最宽基本类型大小的整数倍。
union:
1,所有成员中最长的那个;
2,整个结构体大小必须是最宽成员大小的整数倍。
enum:
1, 定义一个常量集合,当int存储,都为4。
因此:在定义结构体成员时为节省内存,一般将同一类型定义在一起,长类型放在最开始或者最后。
附:struct与union相互嵌套的技巧
代码语言:javascript复制#include <stdlib.h>
#include <stdio.h>
// 参考 Glibc库源码 sig_info.h
typedef struct info{
int age;
union {
int code;
struct {
int pid;
int uid;
} id;
struct {
int KM;
char *addr_name;
} address;
} u;
} info_t;
#define code u.code
#define pid u.id.pid
#define uid u.id.uid
#define KM u.address.KM
#define addr_name u.address.addr_name
int main(int argc, char **argv)
{
info_t info;
info.age = 20;
info.code = 5;
printf("age = %dn", info.age); // 20
printf("code = %dn", info.code); // 5
printf("----------------------n");
info.pid = 123;
printf("age = %dn", info.age); // 20
printf("code = %dn", info.code); // 123, 因为code变量与id变量共用一块内存
printf("pid = %dn", info.pid); // 123
printf("----------------------n");
info.KM = 789;
printf("age = %dn", info.age); // 20
printf("code = %dn", info.code); // 789, 因为code变量与address变量共用一块内存
printf("pid = %dn", info.pid); // 789, 因为id变量与address变量共用一块内存
printf("KM = %dn", info.KM); // 789
return 0;
}