结构体大小的计算

    技术2022-05-20  29

    字节对齐原则

    结构体默认的字节对齐一般满足三个准则:

    1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

    2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

    3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

    通过这三个原则,就不难理解下面两个struct的差异了.

    结构体(struct)的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。先看下面定义的两个结构体.

    struct {   char a;   short b;   char c; }S1;

    struct {  char  a;  char  b;  short c; }S2;

    分别用程序测试得出sizeof(S1)=6 , sizeof(S2)=4

    可见,虽然两个结构体所含的元素相同,但因为其中存放的元素类型顺序不一样,所占字节也出现差异。这就是字节对齐原因。通过字节对齐,有助于加快计算机的取数速度,否则就得多花指令周期。

    对于struct S1, 为了使short变量满足字节对其准则(2), 即其存储位置相对于结构体首地址的offset是自身大小(short占2个字节)的整数倍,必须在字节a后面填充一个字节以对齐;再由准则(3),为了满足结构体总大小为short大小的整数倍,必须再在c后面填充一个字节。

    对于struct S2, 却不必如上所述的填充字节,因为其直接顺序存储已经满足了对齐准则。

    如果将上面两个结构体中的short都改为int(占4个字节), 那么会怎么样呢? 程序得出sizeof(S1)=12, sizeof(S2)=8 利用上面的准则,也不难计算得出这样的结果。S1中在a后面填充3个字节、在c后面填充3个字节,这样一共12个字节;S2中在a、b顺序存储之后填充两个字节用以对其,这样一共就8个字节。

    当然,在某些时候也可以设置字节对齐方式。这就需要使用 #pragma pack 。

    #pragma pack(push) //压栈保存

    #pragma pack(1)// 设置1字节对齐

    struct {   char a;   short b;   char c; }S1;

    #pragma pack(pop) // 恢复先前设置

    如上所示,将对其方式设为1字节对齐,那么S1就不填充字节,sizeof为各元素所占字节之和即4。这一点在从外部2进制文件中读入struct大小的数据到struct中,是很有用的.

    此外,对于空结构体(即内部没有任何元素),在UNIX平台gcc4.1下的sizeof 为0,而在Windows平台VC6下得出的sizeof却为1!

    //-------------------------

    #pragma pack(push,1) typedef struct dummy_data_t { int nDummy; double dDummy1; double dDummy2; } DUMMY_DATA; #pragma pack(pop)

    此时sizeof(dummy_data_t)的大小为20(4+8+8),而不是24(8+8+8)!

    再补充一点:      可以使用 #pragma pack(1) 预编译命令来指定对齐方式;#pragma pack(1)表示按字节对齐。这个对齐时所可以指定的值为:1、2、4、8、16,除了这些以外目前好像都是非法的。

    另外,想要程序获得最佳的执行效率,那个所用到的各个变量的长度都应该是系统位数的整数倍。比如:程序要运行在32位的操作系统上,那么4个字节长的int型将会是效率最高的变量。其它的如结构体等等,都最好能保证其大小为4字节的整数倍.

    单片机中结构体的大小不遵循字节对齐原则,按实际字节大小计算。


    最新回复(0)