sizeof总是一样吗?

时间:2019-12-13 15:40:41

标签: c++ sizeof

我对类的结构,填充以及由此产生的sizeof类有一个快速的问题。在下面的示例中,在我测试过的每个编译器上,sizeof A的结果始终为40个字节,这对我来说很有意义。

#include <iostream>
class A {
    int a, b; // 4 + 4
    short c;  // + 2
    double f; // not currently 8 byte aligned. Currently 10 bytes, so pad 6 extra bytes, so: + 6 + 8
    char w;   // + 1
    bool d;   // + 1
    double g; // not currently 8 byte aligned. Currently 26 bytes, so pad 6 extra bytes, so: + 6 + 8

    // 4 + 4 + 2 + 6 + 8 + 1 + 1 + 6 + 8 = 40
};

int main() {
    std::cout << sizeof( A );
}

我的问题是,这永远是真的吗? (假设每个成员的alignof和size不变)。我知道我可以对其重新排序,以使double首先出现,并且缩小到32个字节。但是编译器可以做出此决定吗?还是程序员一贯的责任? (我假设编译器无法重新排序)

4 个答案:

答案 0 :(得分:5)

不允许编译器对成员进行重新排序,因为它们都具有相同的访问级别。因此,例如,如果有一个public成员,则编译器可以对您的成员变量重新排序。

参考:https://timsong-cpp.github.io/cppwp/class.mem#19

C ++标准不保证类的大小,除了必须保证成员可以单独寻址之外。

答案 1 :(得分:5)

sizeof(A)在您的程序执行中将始终相同。如果您更改成员的顺序或A的打包和重新编译方式,则可以/将获得不同的值。如果使用其他编译器进行编译,则大小也会改变。它也可以在使用同一编译器的不同机器上更改,因为不同机器的基本类型大小可能不同。

长话短说,如果您依赖于特定的班级人数,请添加一个static_assert来进行检查。这样,如果确实发生更改,您将得到一个不错的编译器错误,而不是可能的UB。

  

我知道我可以重新排序,以便双打优先,并且缩小到32个字节;但是编译器可以做出这个决定吗?

不,由于您的类是标准布局类,并且必须按声明的顺序将所有成员布置在内存中,因此编译器无法对成员进行重新排序以更好地打包。

答案 2 :(得分:3)

  

sizeof总是一样吗?

sizeof是编译时间常数。因此,对于已编译的任何程序,sizeof在两次执行之间不会改变。但是,对于程序的不同编译没有这样的保证。实际上,当为另一个系统编译程序时,即使基本类型的sizeof和alignof也不同,这是很典型的。

  

我知道我可以重新排序...编译器可以做出此决定吗?

对标准布局类有限制。确保第一个成员具有与超级对象相同的地址。同样,对于在声明顺序开始时具有相同类型成员的相同顺序的任何此类类,可以通过单独的联合成员访问“公共初始序列”,这实际上意味着它们必须具有相同的地址,这实际上是有效的。防止成员的任何重新排序,因为编译器无法知道其他可能具有潜在共享公共初始序列的类。 A是标准布局类。

这些限制不适用于非标准布局类,使用该类可以使编译器更加宽松。据我所知,该语言不会阻止编译器选择非标准布局类的成员顺序。但是实际上,为了将单独编译的目标文件链接在一起,这些目标文件必须符合相同的二进制接口,即它们需要具有相同的类型表示形式。如果编译器将一种布局用于一种编译,而将另一种布局用于另一种编译,则会破坏ABI。因此,无论编译器选择什么顺序,它都应该坚持下去。任何打算兼容的编译器都应使用相同的ABI。对于值得GCC使用的Itanium ABI,它指定:

  

2.4非POD类类型

     

II。虚拟基地以外的成员分配

     

对于每个数据组件D(首先是C的主要基类,如果有的话,然后是按声明顺序的非主要,非虚拟直接基类,然后是非静态数据成员和未命名的位字段按声明顺序)...


  

还是程序员永远的责任? (我假设编译器无法重新排序)

对于程序员来说,最好假设子对象按声明顺序排列,并以最小化填充的方式选择该顺序。为了访问非标准布局类的内存,最好不要假设子对象的顺序。

答案 3 :(得分:1)

不允许编译器对类中的属性重新排序(此顺序在构造和解构成员时会使用,因此可能会改变程序的含义)。

但是,您也不能指望sizeof总是相同的结果。如果出现了64位int比32位更有意义的架构怎么办?在这种情况下,尺寸会更大。

相关问题