【问题标题】:Is sizeof class guaranteed to contain size of elements only [duplicate]sizeof 类是否保证仅包含元素的大小 [重复]
【发布时间】:2013-07-10 00:47:22
【问题描述】:

给定示例类

class test
{
public:
test();
~test();
void someMethod();
void someOtherMethod();

private:
int var;
};

sizeof(test) == sizeof(int),或者我们不能做出这样的假设?它依赖于平台/编译器吗?

编辑:

这样做的动机是通过流读/写类。类确实包含一个整数,并带有一些方便的访问方法 - 整数的最高位字节保留用于标志,3 个低位字节表示整数 24 位数。鉴于此,想法是编写此类变量的数组,并在需要时将它们作为纯 int 读取。引用为具有可能答案的问题并未解决该方面 - 更多的是关于填充多个元素。

【问题讨论】:

  • 虽然我怀疑任何编译器都会在其中添加填充,但它可以。
  • 请注意,您的类没有虚函数,也没有虚基类等。这简化了它。如果您的班级有任何虚拟,您可以相当确信其大小将大于sizeof(int)(尽管标准不能保证这一点)。就目前而言,很可能是sizeof(test) == sizeof(int),但标准肯定不能保证这一点(编译器可以使其更大;它可能无法使其更小)。
  • 我必须指出,除非您将数据移入或移出程序,否则您通常不应该关心类的大小与成员的大小不同。这是一个微观问题。除非您可以证明类的大小是代码中的特定瓶颈,否则采取措施确保其具有特定大小是过早的微优化。可能会产生负面影响的一种。
  • @John Dibling 是的,这样做的动机是通过 stream.write((char*)classVar,sizeof(test)); 之类的流读取/写入整个类;
  • @IlyaKobelevskiy:好的,这是正当的理由。这样做时要注意字节顺序。

标签: c++ sizeof


【解决方案1】:

一般而言,不,您不能假设某个任意类的大小只是其成员大小的聚合。一般来说,你也不应该关心*。编译器可以并且将更改您的类的大小,以便它们的大小是某些特定字节数的倍数。这样做的原因是为了提高性能。每个平台的字节数是不同的。

在这个具体的例子中,sizeof (test) == sizeof (int) 实际上可能是这种情况,但我怀疑这是提示这个问题的真实代码。

有一些方法可以确保它确实如此,但它们依赖于特定于平台的功能。

首先,确保您的班级是 POD*,并且所有成员本身都是 POD。

其次,将packing设置为1个字节。在 GCC 和 MSVC 下,执行此操作的指令类似于:

#pragma pack (1)

您应该在不是严格需要时关闭此包装,因为它可能会对性能产生负面影响:

#pragma pack (push, 1)

class test
{
public:
  void someMethod();
  void someOtherMethod();

  int var;
};

#pragma pack (pop)

请注意,上面我删除了private 部分。如果您的类具有非static privateprotected 数据成员,则该类不是 POD。出于同样的原因,我还删除了默认的构造函数和析构函数。

在 MSVC 和 GCC 下,sizeof(test) 将等于 sizeof(int)


POD:普通旧数据类型。为了使类(或结构)成为 POD,它必须没有用户定义的析构函数或构造函数、复制赋值运算符,并且没有指向成员的类型指针的非static 成员。此外,它必须没有virtuals、没有privateprotectedstatic 成员并且没有基类。此外,它所拥有的任何非static 数据成员必须本身就是 POD。换句话说,只是普通的旧(公共)数据。


“你也不应该在意。”通常,您需要确保某个类的大小与成员的大小完全相同的唯一时间是在系统的边界处。例如,当通过套接字将数据移入或移出程序时。编译器填充你的类是有原因的。除非您有特定的、可证明的原因,否则您不应在此覆盖编译器。

【讨论】:

  • static_assert(sizeof(test) == sizeof(int)) 在这里会起到很大的帮助。
  • 非常感谢这个非常详细的回答。即使在 msvc 上没有对齐强制大小匹配。我不会强制执行对齐,而是采用 Cory Nelson 建议的 static_assert 方法 - 只要可以在编译时检测到问题,它就是安全的。
  • BTW POD 不是必需的,只有 standard-layout
【解决方案2】:

你不能做出这样的假设。

允许编译器添加填充以提高性能。也许您的目标系统只能读取 64 位值。读取较小的值需要读取 64 位,然后屏蔽为 32 位。在这样的系统上,将类填充到 64 位会更有效。

如果你真的需要一个类或结构体的大小正好符合你的要求,那么几乎每个编译器都有属性或编译指示来控制填充。

【讨论】:

  • 那么int 也会被填充...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 2012-02-13
  • 2013-05-01
  • 2021-12-14
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
相关资源
最近更新 更多