Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;结构填充和字段填充 是否有C++中的任何东西阻止编译器打包它的字段,以便一个字段可以与另一个字段的填充重叠?_C++_Padding - Fatal编程技术网

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);