从C语言结构对齐重谈变量存放地址与内存分配

【@.1 结构体对齐】

@->1.1

如果你看过我的这一篇博客,一定会对字节的大小端对齐方式有了重新的认识。简单回顾一下,对于我们常用的小端对齐方式,一个数据类型其高位数据存放在地址高位,地位数据在地址低位,如下图所示↓

 

这种规律对于我们的基本数据类型是很好理解的,但是对于像结构、联合等一类聚合类型(Aggregate)来说,存储时在内存的排布是怎样的?大小又是怎样的?我们来做实验。

*@->我们会经常用到下面几个宏分别打印变量地址、大小、格式化值输出、十六进制值输出↓

   #define Prt_ADDR(var)   printf("addr:  0x%p  \’"#var"’\n",&(var))    #define Prt_SIZE(var)   printf("Size of \’"#var"’: %dByte\n",(int)sizeof(var))   #define Prt_VALU_F(var,format)   printf(" valu: "#format"  \’"#var"’\n",var)   #define Prt_VALU(var)   Prt_VALU_F(var,0x%p)

*@->如果你没有C语言编译环境可以参考我的博客配置一个命令行gcc编译环境,或者基于gcc的eclipse。

考虑下面代码,

 

#include <stdio.h>#define Prt_ADDR(var) printf("addr: 0x%p \’"#var"’\n",&(var))#define Prt_SIZE(var) printf("Size of \’"#var"’: %dByte\n",(int)sizeof(var))#define Prt_VALU_F(var,format) printf(" valu: "#format" \’"#var"’\n",var)#define Prt_VALU(var) Prt_VALU_F(var,0x%p)typedef struct{char a;char b;char c;char d;} MyType,*pMyType; main(){pMyType pIns; final;//拼接目标变量pIns->a=0xAA;pIns->b=0xBB;pIns->c=0xCC;pIns->d=0xDD;final = *(unsigned int *)pIns; //拼接结构到int类型变量 Prt_VALU(final);return 0;}

上面代码定义了一个含有4个char成员的结构,MyType和其指针pMyTYpe。新建一个实例pIns,赋值内部的四个成员,再将整体拼接到int类型的变量final中。MyType中只有四个char类型,所以该结构大小为4Byte(可以用sizeof观察),而32位CPU中int类型也是4Byte所以大小正好合适,就看顺序,你认为最终的顺序是“0xAABBCCDD”,还是“0xDDCCBBAA”?

下面是输出结果(我用的eclipse+CDT)。

为什么?

结构体中地址的高低位对齐的规律是什么?

我们说,局部变量都存放在栈(stack)里,程序运行时栈的生长规律是从地址高到地址低。C语言到头来讲是一个顺序运行的语言,随着程序运行,栈中的地址依次往下走。遇到自定义结构MyType的变量Ins时(我们程序里写的是指针pIns,道理一样),首先计算出MyType所需的大小,这里是4Byte,在栈里开辟一片4Byte的空间,其最低端就是这个结构的入口地址(而不是最上端!)。进入这个结构后,依次往上放结构中的成员,因此结构中第一个成员a在最下面,d在最上面。联系到我们的小端(little-endian)对齐,因此最后输出的结果是按照高位到低位,d-c-b-a的顺序输出一个完整的数。因此最终的final=0xDDCCBBAA。

IN A NUTSHELL

结构体中的成员按照定义的顺序其存储地址依次增长。

@->1.2

之前我们提到一句,遇到一个结构体时首先计算其大小,再从栈上开辟相应区域。那么这个大小是怎么计算的?

typedef struct{char a;int b;char c;char d;} T1,*pT1;typedef struct{char a;char b;char c;int d;} T2,*pT2;

现在计算上面定义的两个结构体T1,T2的大小是多少?可以通过下面代码打印

#include <stdio.h>#define Prt_ADDR(var) printf("addr: 0x%p \’"#var"’\n",&(var))#define Prt_SIZE(var) printf("Size of \’"#var"’: %dByte\n",(int)sizeof(var))#define Prt_VALU_F(var,format) printf(" valu: "#format" \’"#var"’\n",var)#define Prt_VALU(var) Prt_VALU_F(var,0x%p)typedef struct{char a;int b;char c;char d;} T1,*pT1;typedef struct{char a;char b;char c;int d;} T2,*pT2;int main(){T1 Ins1;T2 Ins2;Prt_SIZE(Ins1);Prt_SIZE(Ins2);}

其结果如下↓

参考这篇文章,总结结构对齐原则是:

当眼泪流尽的时候,留下的应该是坚强。

从C语言结构对齐重谈变量存放地址与内存分配

相关文章:

你感兴趣的文章:

标签云: