我编写了CMyObject类,如下所示:

class CMyObject
{
public:

CMyOjbect(void) {};
virtual ~CMyOjbect(void) {};

public:
    ULONGLONG m_uField1;
    UINT m_uField2;
    BOOL m_bField3;
    int m_iField4;
    BOOL m_bField5;
}

为了减小CMyObject的大小,我将其更改为:
class CMyObject
{
public:

CMyOjbect(void) {};
virtual ~CMyOjbect(void) {};

public:
    ULONGLONG m_uField1;
    UINT m_uField2;

    short m_sField4;    // Change from int to short, since short is enough for the data range

    unsigned m_bField3: 1;      // Change field 3 and 5 from BOOL to bit field to save spaces
    unsigned m_bField5: 1;
}

但是,sizeof(CMyObject)仍然没有更改,为什么?

我可以在pargma pack(1)中使用class打包所有成员变量,如下所示:
pargma pack(1)

class CMyObject
{
public:

CMyOjbect(void) {};
virtual ~CMyOjbect(void) {};

public:
    ULONGLONG m_uField1;
    UINT m_uField2;

    short m_sField4;    // Change from int to short, since short is enough for the data range

    unsigned m_bField3: 1;      // Change field 3 and 5 from BOOL to bit field to save spaces
    unsigned m_bField5: 1;
}

pargma pack(0)

最佳答案

由于您是ULONGLONG的第一个成员,因此您的结构将具有8字节(64位)的对齐方式。假设使用32位整数,则第一个版本使用18个字节,这将需要24个字节来存储。 (大大小小的成员散布着,这使事情变得更糟,但是根据我的判断,这并不能改变答案。)您的第二个版本也占用18个字节:

  • m_uField1 8字节
  • m_uField2的4个字节
  • m_sField4的2个字节
  • 两个unsigned位字段的4个字节(将具有4个字节的对齐方式,因此还将在m_sField4之后注入(inject)2个字节的填充)

  • 如果您切换到short unsigned m_bField3:1short unsigned m_bField4:1,我认为您的结构很有可能会变小并且仅适合16个字节。
    #pragma pack的使用不可移植,因此我无法在此处发表评论,但可能会缩小结构的大小。不过,我猜可能不会,因为通常它可以更好地补偿具有对齐方式的成员的非最佳排序,并且根据我的判断,您的变量本身太大了。 (但是,删除ULONGLONG上的对齐要求可能会缩小任一版本的结构大小,而#pragma pack可能会这样做。)

    正如@slater所提到的,为了减小结构的大小和填充,您应该声明大小相似的成员变量彼此相邻。以减小的大小顺序声明变量是一个很好的经验法则,这将趋于使填充最小化并利用一致的对齐要求。

    但是,结构的大小并不总是最重要的问题。成员在构造函数中按声明顺序进行初始化,对于某些类来说,这很重要,因此您应该考虑到这一点。此外,如果您的结构跨越多条缓存行并且将由多个线程同时使用,则理想情况下,应将在同一缓存行中一起使用的变量和在单独的缓存行中未一起使用的变量放在一起,以减少/消除错误分享。

    10-02 05:08