一次紧急线上事故引发的严重问题

2022-06-16 16:41:46 浏览数 (2)

整个过程大概是这样的:

甲方和乙方接口需要数据传输,比如 甲方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;
}

0 人点赞