【问题标题】:Object size in c++ is unpredictable [closed]C ++中的对象大小是不可预测的[关闭]
【发布时间】:2014-09-25 12:50:33
【问题描述】:
#include<iostream>
using namespace std;
class Test
{
    int a;
    double d;
    char c;
};

int main()
{
    cout<<sizeof(int)<<endl;
    cout<<sizeof(double)<<endl;
    cout<<sizeof(char)<<endl;
    cout<<sizeof(Test)<<endl;
    Test sobj;
    Test *dobj = new Test();
    cout<<dobj<<endl;
    dobj++;
    cout<<dobj<<endl;
    cout<<sizeof(sobj)<<endl;
    cout<<sizeof(dobj)<<endl;

    return 0;
}

输出:

4
8
1
24
00380A08
00380A20
24
4

这里我的问题是当我们使用 sizeof 运算符打印类的大小时,它显示为 24 字节,因为没有应用填充它很清楚,但是当我看到地址之间的差异时,它显示类大小为 12 字节,如何正在分配内存..??

【问题讨论】:

  • 你在哪里看到 12 个字节?
  • 0x00380A20 - 0x00380A08 = 0x18 = 24(基数为 10)。您示例中的地址以 16 进制(十六进制)打印。
  • 为什么你认为没有应用填充?
  • 肯定应用了填充:coliru.stacked-crooked.com/a/eb6a1b3721b875f0 您的示例对应于 Layout1,其中 int 后有填充(以在 8 字节边界上对齐双精度)和 char 后有填充(使整个结构在 8 字节边界上对齐),为结构提供总共 24 个字节。其他两种布局可以将 int 和 char 字段打包到同一个 8 字节区域中,因此结构的大小为 16。

标签: c++ object memory size sizeof


【解决方案1】:

地址是十六进制的(从A 可以看到)。 0x20 是十进制的 32:差(十进制)不是 20 - 8,而是 32 - 8 = 24。

【讨论】:

  • 0x20=32 和 32-8 = 24 怎么样
  • @Calvin 是的,谢谢。看来我不能做涉及两位数的数学运算。
【解决方案2】:

首先,您的困惑来自以十六进制(以 16 为基数)打印的地址。两个地址的不同部分是 0x20(十进制为 32)和 0x08(十进制为 8)。这两个数字之间的差是 0x18(十六进制)或十进制的 24。

其次,肯定会应用一些填充。根据各种类型大小的数字,在您的问题中,请考虑以下代码,该代码以三种不同的顺序定义结构的字段:

(现场示例http://coliru.stacked-crooked.com/a/eb6a1b3721b875f0

#include <iostream>

struct Layout1 {
    int a;
    double b;
    char c;
};

struct Layout2 {
    int a;
    char b;
    double c;
};

struct Layout3 {
    double a;
    int b;
    char c;
};

int main() {
    std::cout << sizeof(Layout1) << "\n";
    std::cout << sizeof(Layout2) << "\n";
    std::cout << sizeof(Layout3) << "\n";
    return 0;
}

请记住,在这个例子中,一个 double 是 8 个字节,一个 int 是 4 个字节,一个 char 是 1 个字节。每个结构的布局如下,其中i 表示 int 的一个字节,c 表示 char,d 表示 double 的一个字节。符号- 表示一个字节的填充。

                    1 1 1 1 1 1 1 1 1 1 2 2 2 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
i i i i - - - - d d d d d d d d c - - - - - - -  // layout 1
i i i i c - - - d d d d d d d d                  // layout 2
d d d d d d d d i i i i c - - -                  // layout 3

在第一个布局中,double 成员必须在 8 字节边界上对齐,因此在 int 成员之后会得到四个字节的填充。整个结构也必须与其成员的最严格对齐方式相同,即双精度。因此,在 char 成员之后有 7 个字节的填充。

在第二种布局中,double 必须仍然在 8 字节边界上,但 char 不需要;它可以在 int 之后立即打包,在 double 之前只留下三个字节的填充。由于结构以双精度结尾,因此不需要结尾填充。

在第三个布局中,double 开始结构体,int(具有 4 字节对齐)可以紧随其后(因为 8 是 4 的倍数)。 char(单字节对齐)可以跟在 int 之后,但同样整个结构需要在 8 字节边界上对齐,所以在 char 字段之后有 3 个字节的填充。

因此上面的程序会输出:

24
16
16

【讨论】:

  • 大家好,非常感谢您的明确解释。我知道填充,但我错误地写了“没有应用填充”而不是“应用了填充”。并且关于地址的差异被清除。 :-)
  • 如果您犯了一个错误,您应该编辑您的问题以更正它。
猜你喜欢
  • 2011-04-27
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-27
  • 2020-10-18
  • 2010-09-25
  • 1970-01-01
  • 2014-08-06
相关资源
最近更新 更多