整個過程大概是這樣的:
甲方和乙方接口需要資料傳輸,比如 甲方AA傳遞到乙方BB,乙方想用甲方AA中的資料,由于某方後期修改了自己的定義,導緻sizeof不統一,整個系統發生了崩盤,引發了一次嚴重的線上事故。
甲方AA:
typedef struct aa
{
int id;
char a[6];
enum day{
one,
two,
three =4,
four = 12
};
double w;
float h;
long g;
}AA;
複制
乙方BB:
typedef struct bb
{
int id;
char a[3];
enum day{
one,
two,
three =4,
four = 100
};
double w;
float h;
long g;
}BB;
複制
雙方通信:
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,而乙方得到的确是越界的負值 ,引發了系統崩潰。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcuEjZkBDOmZ2M1kTYmN2NkhDO4MzMwITM3QzMlRmN4UGMvw1M4UTMzgTOtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
類型 | 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互相嵌套的技巧
#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 = %d\n", info.age); // 20
printf("code = %d\n", info.code); // 5
printf("----------------------\n");
info.pid = 123;
printf("age = %d\n", info.age); // 20
printf("code = %d\n", info.code); // 123, 因為code變量與id變量共用一塊記憶體
printf("pid = %d\n", info.pid); // 123
printf("----------------------\n");
info.KM = 789;
printf("age = %d\n", info.age); // 20
printf("code = %d\n", info.code); // 789, 因為code變量與address變量共用一塊記憶體
printf("pid = %d\n", info.pid); // 789, 因為id變量與address變量共用一塊記憶體
printf("KM = %d\n", info.KM); // 789
return 0;
}
複制