C++中#pragma pack(N)计算sizeof

前言

以前在学校就不喜欢C++,很多东西可读性太差,而且半点不拟人化。但是没法,有时候工作中要用到。C++有些基础细节记不得了,遇到一点儿又弄懂一点吧。

举例

在32位机器上,下列代码中:

#pragma pack(2)

class A
{
    int i;

    union U
    {

        char buff[13];

        int i;

    }u;

    void foo() {    }

    typedef char* (*f)(void*);

    enum{ red, green, blue } color;
}a;

sizeof(a)的值是()

A、20 B、21 C、22 D、24 E、非以上选项

答案:C,void foo() { } ,typedef char* (f)(void);不占字节,枚举占4个字节,union按最大的变量所占字节算,占14个字节,int占4个字节,4+14+4=22。如果改为 #pragma pack(4), 结果就为 24。

下面来看下具分析:

pragma pack规定的对齐长度,实际使用的规则是:

结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。

而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack指定值 之间,较小的那个进行。

#pragma pack(4)

class TestB
{
public:

    int aa; //第一个成员,放在[0,3]偏移的位置,

    char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。

    short int b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。

    char c; //第四个,自身长为1,放在[8]的位置。

};

这个类实际占据的内存空间是8字节

内存对齐需要遵循:
1,前面的地址必须是后面的地址的正数倍,不然要补齐;
2,整个Struct的大小必须是最大字节的整数倍。

所以car a跟 short b之间需要插入一个空字节(要求1)。

而类之间的占用,按照类内部最大的成员的长度,和#pragma pack规定的值之中较小的一个对齐的。

所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。

[0-8]->9字节按照4字节整数倍的结果是12,所以sizeof(TestB)是12。

如果:

#pragma pack(2)
class TestB
  {
  public:
    int aa; //第一个成员,放在[0,3]偏移的位置,
    char a; //第二个成员,自身长为1,#pragma pack(2),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
    short b; //第三个成员,自身长2,#pragma pack(2),取2,按2字节对齐,所以放在偏移[6,7]的位置。
    char c; //第四个,自身长为1,放在[8]的位置。
  };
//可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。
//所以 sizeof(TestB)是10。

最后,现在去掉第一个成员变量为如下代码:

 #pragma pack(4)
  class TestC
  {
  public:
    char a;//第一个成员,放在[0]偏移的位置,
    short b;//第二个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[2,3]的位置。
    char c;//第三个,自身长为1,放在[4]的位置。
  };
//整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6
//所以sizeof(TestC)是6。

整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6,所以sizeof(TestC)是6。

猜你喜欢

转载自blog.csdn.net/Jason_Lee155/article/details/129764847