结构体字节对齐及#pragma pack()的使用

这两天遇到结构体字节对齐的问题,搞一搞~~~~~

1、结构体怎么对齐的呢?搞一个小代码看一下。

结构体字节对齐及#pragma pack()的使用_第1张图片

很简单的一段代码,就是打印结构体的大小以及结构体内部每个变量所在的地址,程序执行了两次,程序中结构体内的变量是一样的,只是顺序不同,可以发现实际所占的内存字节数是不相同的。

为什么不同呢?这就是结构体字节对齐的问题了,仔细观察每个变量的起始地址可以发现问题所在。

结构体字节对齐:每个变量的起始地址要是变量自身大小的整数倍,整个结构体的大小是内部最大变量的整数倍

接着看一个内容多的结构体:

结构体字节对齐及#pragma pack()的使用_第2张图片仔细观察总大小和每一个变量的起始地址,每个变量的起始地址都是自身的整数倍,总大小是最大变量的整数倍。

那么问题来了,在工程项目中结构体字节对齐会给我们带来很多问题,比如按地址偏移量取数据会拿不到自己想要的数据,或者通信双方通信的实际字节数和预想的不一样,那么#pragma pack(push)、#pragma pack(n)、#pragma pack(pop)就来了。

2、#pragma pack()

这个玩意是干啥用的,接着看代码~~~

#include
#include

#pragma pack(push,1)
typedef struct {
    char a;
    short b;
    char c;            
}AA;
#pragma pack(pop)
typedef struct {
    char a;    
    short b;    
    char c;
}BB;
int main()
{
    int i = 0;
    char bufa[6];
    char bufb[6];
    AA aa = {2,3,4};                                         
    BB bb = {2,3,4};                                                                                                                                
    AA *a = NULL;                                                     
    BB *b = NULL;                                                      
    
    a = &aa;
    b = &bb;                                                                
                                                                               
    memset(bufa,0,sizeof(bufa));                             
    memset(bufb,0,sizeof(bufb));                               

    memcpy(bufa,a,sizeof(aa));                     
    memcpy(bufb,b,sizeof(bb));                               

    printf("AA==%u\n",sizeof(aa));                          
    printf("%d\n",&aa.a);
    printf("%d\n",&aa.b);
    printf("%d\n",&aa.c);
    
    for(i = 0;i<6;i++)
    {
        printf("%d\n",bufa[i]);
    }

    printf("BB==%u\n",sizeof(bb));
    printf("%d\n",&bb.a);
    printf("%d\n",&bb.b);
    printf("%d\n",&bb.c);

    for(i = 0;i<6;i++)
    {
        printf("%d\n",bufb[i]);
    }
    return 0;
}

结构体字节对齐及#pragma pack()的使用_第3张图片

  程序很简单,初始化的时候赋值,再将值cp到数组中,再将数组中的内容打印输出,仔细看输出结果,两个相同的结构体大小并不一样,AA 占了4个字节,BB占了6个字节,并且数组中的4所在的位置也不一样,在仔细变量的起始地址,发现AA的第二的变量的起始地址并没有按照之前说的整数分配而是紧挨着上一个字节,这就是#pragma pack(push,1)的作用了。


#pragma pack(push,1)和#pragma pack(push),#pragma pack(1)是一个道理,这个意思就是告诉编译器,我就想一个字节对齐,你不要给我乱搞,然后编译器就不会擅自给你对齐了。


接着看BB,好像又被编译器搞了,这就是#pragma pack(pop)的作用了,

#pragma pack(push,1)是将编译器自己的对齐方式先压入栈保存起来,并告诉编译器下面的就按照1字节对齐,只到遇到#pragma pack(pop)将原来的对齐方式在释放出来。这也是工程代码中经常用到的。

你可能感兴趣的:(C语言)