C++;结构填充和字段填充 是否有C++中的任何东西阻止编译器打包它的字段,以便一个字段可以与另一个字段的填充重叠?
继承时允许(可能通过空基类优化)。为了说明场景,请考虑下面的片段:C++;结构填充和字段填充 是否有C++中的任何东西阻止编译器打包它的字段,以便一个字段可以与另一个字段的填充重叠?,c++,padding,C++,Padding,继承时允许(可能通过空基类优化)。为了说明场景,请考虑下面的片段: #include <cstdint> #include <cstdlib> struct A { A() { a2 = rand(); } // force non-POD uint32_t a1; uint16_t a2; }; struct B { A b1; uint16_t b2; }; struct C : A { uint16_t c; }
#include <cstdint>
#include <cstdlib>
struct A {
A() { a2 = rand(); } // force non-POD
uint32_t a1;
uint16_t a2;
};
struct B {
A b1;
uint16_t b2;
};
struct C : A {
uint16_t c;
};
(如果A
被做成一个POD,那么B
和C
都会有填充,大概是因为offsetof()
是允许的,优化会变得可见,可能会破坏代码)
我很好奇,在
B
案例中,是否有一个很好的理由不以最佳方式打包字段?一个struct
不会重叠另一个struct
,即使它重叠的struct
元素是“填充”的
想象一下:
A a;
B x;
memcpy(&x.b1, a, sizeof(a));
如果B
被“打包”,使得b2
正好位于A
中的a2
元素旁边,那么它将被A
中的任何垃圾所覆盖-这可能不是此类代码的原始作者所期望的(我很确定标准中说上述必须起作用)
但是,第二个示例不是包含另一个struct
的struct
。它是一个从另一个struct
继承的struct
。在这种情况下,原始struct
A不能独立于其他struct
成员(在这种情况下c
)使用。该标准将有一节规定,在继承自a
的C
类型的struct
上复制a
类型的struct
将是“未定义的行为”,允许编译器在这种情况下“打包”
因此,这是两种不同的情况,它们有不同的限制。
我很好奇,在B情况下,没有对字段进行最佳打包有什么好的理由吗?
在这种情况下,编译器确保类型适合4字节边界(对齐是一个简单的过程)。因此,它确保sizeof(A)
为8字节。如果它将B
打包为仅占用8个字节,这意味着sizeof(b1)
必须为6,因此sizeof(b1)!=sizeof(A)
,这没有意义
sizeof(b1)
等于sizeof(A)
的原因是sizeof
运算符不计算表达式-它是在编译时计算的,因此它对表达式类型b1
进行操作,即A
这意味着您将以以下方式结束:
B b;
sizeof(b.b1); // => 8, as b1 type is B
sizeof(b); // => 8 (although b consists of b1 and c);
当您从A继承C时,它是一种全新的类型,因此编译器可以根据需要对其进行对齐。
不按哪个标准对字段进行最佳打包的原因是什么?Zdeslvav,我猜是大小。出于好奇:您能分享一下如何使用Clang和GCC打印这些漂亮的布局吗?提前感谢:)(旁注:您的示例使用的名称来自std
,没有“std:
”限定,也没有使用声明/使用指令;我猜在您的实现中
碰巧包含
,但这不能保证。)布局将从调试信息中拉出+1同样重要的是,结构/类的大小不能小于其成员的大小,这正是如果将b2
打包到b1
的填充中会发生的情况。它可以更大(由于B
成员的结构填充,duh),但它不能更小。这是一个很好的例子。但是,如果A和B是非POD(或者说非标准布局),如果标准定义了复制它们的字节,我会感到惊讶。@WhozCraig我确实记得C保证sizeof()至少是其所有成员的sizeof()之和。然而,这条规则对于非标准布局类型(例如不允许offsetof)是必要的或有意义的,这并不明显。尽管A是“非POD”类型,但并不意味着允许它违反struct
-sizeof(A)
的标准规则,它仍然应该与sizeof(B::b1)
相同,例如,是的。这可能是强制执行此行为的标准的一部分。但是,我想不出标准提供这种保证的好理由(请记住,我们讨论的是非标准布局类型)。大概C++98有机会不提供它(同样,对于非POD类型),我并不完全清楚它没有意义。在C++和非标准布局的世界中,这些属性不需要暴露给程序员。当然,具有不同于其类型的大小的实例不是很有意义的。我认为这取决于您希望从siZeFo()返回值得出什么结论。我的理解是,非标准布局类型不会公开其布局的任何内容。他们也不会对其成员的sizeof()提供这样的保证,这似乎并不牵强。除了分配内存之外,还可以使用SsieOf()在非标准布局类型上使用什么?<代码> > SigeOs< /Cord>返回是由C++标准定义的。没有标准和非标准布局,它们都符合C++规范或编译器被破坏。code>sizeof
可以用于其他方面:实现一些编译时检查、实现countof等。c++11将术语“标准布局”定义为POD类型的布局约束。我仍然无法在标准中找到需要这种填充行为的位置。sizeof并没有在非基元类型上特别严格地定义。我只是在看C++标准,也许它是从C继承的?在脚注77中,它确实明确地说sizeof(A)不必是当C从基类派生时基类所使用的空间量。
B b;
sizeof(b.b1); // => 8, as b1 type is B
sizeof(b); // => 8 (although b consists of b1 and c);