3

可能重复:
为什么结构的 sizeof 不等于每个成员的 sizeof 之和?

给定以下类,没有其他数据成员:

typedef uint32_t id_t;
typedef int64_t loc_t;

class foo:
{
public:
    enum bar : uint8_t
    {
        BAR1,
        BAR2,
        BAR3
    };
private:
    id_t id;
    loc_t  start;
    loc_t  stop;
    bar std;
};

谁能解释为什么:

sizeof( id_t ) 返回 4...
sizeof( loc_t ) 返回 8...
sizeof( bar ) 返回 1...

4+(2*8)+1 = 21

然而:

sizeof( foo ) 返回 32?

删除 bar 枚举类型的 uint8_t 要求只会成功地使 sizeof( bar ) 返回 4 (int) 而 sizeof( foo ) 在 24 正确字节对齐时仍返回 32。

编辑:为什么已经得到令人满意的回答。我感谢每个发表评论的人,因为每个人都带来了不同的细节。

我需要的修复是能够使用 sizeof() 创建文件位置偏移量。因此,当我将 foo 以二进制格式写入文件时,如果我稍后给出它的位置,我可以立即找到它后面的位置。如果我找到一个优雅的解决方案,我会在这里更新。

4

3 回答 3

2

那是因为内存对齐。处理器根据总线宽度获取数据,32 位操作系统将在 4 字节边界上对齐数据,而 64 位操作系统将在 8 字节边界上对齐数据。非对齐内存需要两次内存读取并导致性能下降。

在此处阅读有关内存对齐的所有信息:

  1. http://www.devx.com/tips/Tip/13265
  2. http://msdn.microsoft.com/en-us/library/83ythb65.aspx
于 2012-11-07T00:37:24.183 回答
1

这是由于填充。编译器可能会在您的结构中留下“空格”,以确保结构内的变量对齐良好,以便更有效地访问。

您可以覆盖默认的结构成员对齐方式(至少在 MSVC 中,通过指定#pragma pack.

于 2012-11-07T00:39:46.300 回答
1

由于int64_ts,类型可能是 8 字节对齐的,所以

sizeof(id_t) + 4 bytes padding + 2*sizeof(loc_t) + `sizeof(uint8_t)` + padding up to the next multiple of 8 =
4 + 4 bytes of padding + 16 + 1 + (padding up to the next multiple of 8) =
25 + padding to multiple of 8 =
32

一些编译器对填充有警告(clang 有 -Wpadded):

warning: padding class 'foo' with 4 bytes to align 'start' [-Wpadded]
    loc_t  start;
           ^
warning: padding size of 'foo' with 7 bytes to alignment boundary [-Wpadded]
class foo
      ^

您也可以使用编译器扩展来控制它,例如#pragma pack(1)

#pragma pack(1)
class foo:
{
public:

当然,这样做会降低性能,但 sizeof(foo)在这个系统上,这种方式对我来说是 21。

于 2012-11-07T00:42:05.093 回答