首页 > 其他 > 详细

关于struct结构体填充造成的字节数的问题

时间:2015-03-23 09:43:12      阅读:222      评论:0      收藏:0      [点我收藏+]

有如下的结构体的定义:

<span style="font-size:14px;">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
};</span>
问题, 求对struct进行sizeof的时候, 得到的大小数。

问题解析: 当内存中的值合理对其的时候, 很多机器能够高效的访问。 例如, 按字节寻址的32位机器中, 有两个字节的short型变量必须放在偶数地址上, 而4字节的int型变量, 必须放在4的整数倍地址上。 某些机器甚至根本不能访问没有对齐的地址。 所以必须要求所有的数据正确的对齐。 

为了解决上述问题, 我们要知道, 32位机器, 对于指针变量, 无论是char型还是int型, 指针变量存的都是地址, 都占用4bytes。

下面我们一步一步分析:

<span style="font-size:14px;">struct aa{
    char a;
};</span>
上述在内存中占用1个byte。 

|

<span style="font-size:14px;">struct aa{
    char a;
    int b;
};</span>
上述本来占据5个byte。 但是由于要求int型变量b的地址必须是4的倍数, 所以占用1(for char) + 3 (填充用的) + 4(for int), 故而占用8个bytes。
| - - -| | | |

 

<span style="font-size:14px;"><pre name="code" class="cpp">struct aa{
    char a;
    int b;
    float c;
};</span>


上述占用了12个字节。 因为已经满足4的倍数啦。

| - - -  | | | |   | | | | 

<span style="font-size:14px;">struct aa{
    char a;
    int b;
    float c;
    double d;
};</span>

 上述占用12 + 8个字节。 但是double要求地址offset从8的整数倍开始, 所以填充4个字节, 变成16, 变成8的倍数, 在存下double。 是 12 + 4  + 8 = 24 bytes:

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | |


下面:

<span style="font-size:14px;">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
};</span>
上述占用24 + 8 = 32bytes。虽然要char*pa 变量占用4bytes, 但是 因为要按照double的对其格式。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  - - - - 


<span style="font-size:14px;">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
};</span>

上述占用仍然是32 bytes, 因为最后已经有四个空着的bytes, 仍然满足地址是8的倍数。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | |


<span style="font-size:14px;"><pre name="code" class="cpp">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
};</span>


上述占用时32 + 8 = 40 bytes, 因为 short要按照double的格式对其, 即总的地址要是8的倍数。 

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | | (short) | | - -  - - - -

也就是最后尾部还剩下6个bytes空着了。 试想

<span style="font-size:14px;"><pre name="code" class="cpp"><pre name="code" class="cpp">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
    int f;
};</span>



由于空6个bytes, 必须是4的倍数, 所把最后四个给占用了。 所以当然还是40bytes。 当然是。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | | (short) | | - -  (int) | | | |


接下来, 如果再加一个short, 就变成了48了, 当然是啦:

<span style="font-size:14px;">struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
    int f;
    short g;
};</span>

编译器可能提供用于控制结构体的这种填充。 例如#pragma, 这样我们就可以屏蔽掉变量的对齐方式, 自己设定变量的对齐方式。 

例如编译器提供#pragma pack(n) 来设定变量以n字节对齐的方式。 n 字节的对齐方式指的是, 如果n 大于该变量所占的字节数, 那么偏移量必须满足默认的对齐方式, 如果n 小于变量类型所占的字节数, 那么偏移量必须为n的倍数。 

举例子如下:

<span style="font-size:14px;">#include <iostream>

using namespace std;

#pragma pack(push) // 保持对齐方式
#pragma pack(4) // 设定4字节对齐
struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
};
#pragma pack(pop) // 恢复对齐方式

int main() {

    cout << sizeof(aa) << endl;

    return 0;
}</span>
运行结果如下:

技术分享

分析如下:

4 + 4 + 4 + 8 + 4 + 4 + 4 = 32.

如果我们设置1字节对齐:

<span style="font-size:14px;">#include <iostream>

using namespace std;

#pragma pack(push) // 保持对齐方式
#pragma pack(1) // 设定1字节对齐
struct aa{
    char a;
    int b;
    float c;
    double d;
    char* pa;
    int* pb;
    short e;
};
#pragma pack(pop) // 恢复对齐方式

int main() {

    cout << sizeof(aa) << endl;

    return 0;
}</span>
运行结果为:

技术分享
分析:

 1 + 4 + 4 + 8 + 4 + 4 + 2 = 27. 

okay。 完美解决。 


关于struct结构体填充造成的字节数的问题

原文:http://blog.csdn.net/a130737/article/details/44538917

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!