【问题标题】:C++ Sizeof gives unpredictable results [duplicate]C ++ Sizeof给出了不可预测的结果[重复]
【发布时间】:2012-12-27 18:26:57
【问题描述】:

可能重复:
Why does ‘sizeof’ give wrong measurement?

我有一个名为 CBUFFER_PEROBJECT 的结构:

struct CBUFFER_PEROBJECT
{
    D3DXMATRIX Final;
    D3DXMATRIX Rotation;
};

在另一个班级我这样做:

...
bd.ByteWidth = sizeof(CBUFFER_PEROBJECT); 
...

我发现 D3DXMATRIX 的大小是 64,所以 64+64 = 128(对吗?)。但是我的编译器在和我开玩笑(Visual C++),因为在我调试程序的时候,bd.ByteWidth 变成了 132,所以我去了即时窗口(Visual Studio),然后输入:

sizeof(D3DXMATRIX) + sizeof(D3DXMATRIX)

结果是:

128

但是 bd.ByteWidth 变成了 132,当我在“立即窗口”中输入以下内容时:

sizeof(CBUFFER_PEROBJECT)

它给了我:

128

【问题讨论】:

  • 64 + 64 是 128,根据问题,64 + 64 可能是预期的结果。
  • 根据您的编译器设置,您可以在结构/类上添加填充...您还可以添加指向 vtable 的指针的大小等。
  • CBUFFER_PEROBJECT 不会有 vtable。
  • 发布一个完整但最小的程序来演示问题
  • 看起来像您告诉我们的编译器错误。尝试制作一个暴露它的最小示例。

标签: c++ debugging visual-c++


【解决方案1】:

是的,您混淆了D3DMATRIXD3DXMATRIX(注意第二种类型中的额外X)。第一个是 16 个浮点值的普通矩阵(正好是 64 个字节)。后者是一个类,它显然在结构的某处有 4 个字节的额外数据。也许是一个 vtable 或类似的东西。

如果您将代码编译为 C 而不是 C++,大小将相同,因为提供后者结构的头文件然后是 typedef D3DMATRIX D3DXMATRIX;

请参阅:D3DXMATRIXD3DMATRIX

编辑:这有点像军方的老笑话“如果地图和现实不匹配,那么地图就是正确的”。在这种情况下,如果你不同意编译器,那你就错了。编译器在计算大小时总是正确的。理解为什么编译器得到这个数字,嗯,那是另一回事......通常通过将预期的偏移量与实际发生的情况进行比较来解决,并了解是什么(如果有的话)导致了“差距”。

【讨论】:

  • 代码中用到的D3DMATRIX在哪里?
  • 不是。 D3DXMATRIX 是 - 但由于它是一个类,因此它是占用额外空间的合理解释。至少根据我的经验。
  • 一个更合理的解释是结构对齐。
  • 为什么这更合理 - 64 字节数据后跟 64 字节数据不需要任何地方的 4 字节对齐。
  • 不只是 64 个字节。 D3DXMATRIX 是一种复杂类型。您还必须考虑内部因素。
【解决方案2】:

有时当编译器评估结构声明时,它们会在字段之间添加填充字节。这是因为某些类型在与长度是其长度的倍数的内存地址对齐时表现更好。

我什至可以说你很可能不会在即时窗口中看到这种效果。

鉴于这些理由,这是一个重复的问题。您可以在这里获得更深入的答案:Why isn't sizeof for a struct equal to the sum of sizeof of each member?

【讨论】:

    【解决方案3】:

    您不能仅计算结构的成员大小来计算结构的大小,因为在结构中它还存储了一些额外的信息(程序员看不到)。这就是为什么你得到 132 而不是 128。

    【讨论】:

    • 这种“额外信息”有时可能是调试信息,但很可能来自结构对齐。
    【解决方案4】:

    在这种情况下,最好假设编译器是正确的。这很可能意味着您的项目中有两个不同的CBUFFER_PEROBJECT 定义,但定义略有不同。编译器认为定义 A 的大小为 132,而调试器正在查看大小为 128 的定义 B。您可以通过在每个源文件中创建包含 sizeof(CBUFFER_PEROBJECT) 值的全局变量来测试这一点。然后,您可以在调试器中检查这些全局变量以查看它显示的内容。

    当然,另一种可能性是您的内存被覆盖,而不是由您认为正在设置它的行设置。在这种情况下,像 Purify 或 valgrind 这样的东西可以帮助你找出内存问题。

    【讨论】:

      【解决方案5】:

      您可以使用隐藏的 Visual Studio 编译器切换到 /d1reportSingleClassLayoutSomeType 来告诉您编译器布局是什么。点击链接阅读如何使用开关。

      我为您的示例代码尝试了它,但我没有“D3DXMATRIX”类型。我确实有“D3DMATRIX”,所以我试了一下,得到了:

      1>  class CBUFFER_PEROBJECT size(128):
      1>      +---
      1>   0  | _D3DMATRIX Final
      1>  64  | _D3DMATRIX Rotation
      1>      +---
      

      所以如果你使用开关应该能够告诉你你的结构的确切布局。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-06
        • 2023-03-30
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        • 2018-03-11
        • 2015-08-01
        相关资源
        最近更新 更多