<tfoot id='bxABW'></tfoot>

    <legend id='bxABW'><style id='bxABW'><dir id='bxABW'><q id='bxABW'></q></dir></style></legend>
    <i id='bxABW'><tr id='bxABW'><dt id='bxABW'><q id='bxABW'><span id='bxABW'><b id='bxABW'><form id='bxABW'><ins id='bxABW'></ins><ul id='bxABW'></ul><sub id='bxABW'></sub></form><legend id='bxABW'></legend><bdo id='bxABW'><pre id='bxABW'><center id='bxABW'></center></pre></bdo></b><th id='bxABW'></th></span></q></dt></tr></i><div id='bxABW'><tfoot id='bxABW'></tfoot><dl id='bxABW'><fieldset id='bxABW'></fieldset></dl></div>

        • <bdo id='bxABW'></bdo><ul id='bxABW'></ul>

        <small id='bxABW'></small><noframes id='bxABW'>

      1. 扩展填充结构时,为什么不能在尾部填充中放置额外的字段?

        时间:2023-07-01
          <i id='5cxXp'><tr id='5cxXp'><dt id='5cxXp'><q id='5cxXp'><span id='5cxXp'><b id='5cxXp'><form id='5cxXp'><ins id='5cxXp'></ins><ul id='5cxXp'></ul><sub id='5cxXp'></sub></form><legend id='5cxXp'></legend><bdo id='5cxXp'><pre id='5cxXp'><center id='5cxXp'></center></pre></bdo></b><th id='5cxXp'></th></span></q></dt></tr></i><div id='5cxXp'><tfoot id='5cxXp'></tfoot><dl id='5cxXp'><fieldset id='5cxXp'></fieldset></dl></div>

            <bdo id='5cxXp'></bdo><ul id='5cxXp'></ul>
            • <small id='5cxXp'></small><noframes id='5cxXp'>

                <tbody id='5cxXp'></tbody>
            • <legend id='5cxXp'><style id='5cxXp'><dir id='5cxXp'><q id='5cxXp'></q></dir></style></legend>
              <tfoot id='5cxXp'></tfoot>

                1. 本文介绍了扩展填充结构时,为什么不能在尾部填充中放置额外的字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  让我们考虑结构:

                  struct S1 {
                      int a;
                      char b;
                  };
                  
                  struct S2 {
                      struct S1 s;       /* struct needed to make this compile as C without typedef */
                      char c;
                  };
                  
                  // For the C++ fans
                  struct S3 : S1 {
                      char c;
                  };
                  

                  S1 的大小为 8,这是由于对齐的原因.但是 S2 和 S3 的大小是 12.这意味着编译器将它们构造为:

                  The size of S1 is 8, which is expected due to alignment. But the size of S2 and S3 is 12. Which means the compiler structure them as :

                  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
                  |       a       | b |  padding  | c |  padding  |
                  

                  编译器可以在不破坏对齐约束的情况下将 c 放在 6 7 8 的填充中.阻止它的规则是什么,背后的原因是什么?

                  The compiler could place c in the padding in 6 7 8 without breaking alignment constraints. What is the rule that prevent it, and what is the reason behind it ?

                  推荐答案

                  简短回答(针对问题的 C++ 部分): Itanium ABI for C++ 由于历史原因,禁止使用基的尾部填充POD 类型的子对象.请注意,C++11 没有这样的禁令.相关规则 3.9/2 允许通过其底层表示复制可平凡复制的类型,明确排除基础子对象.

                  Short answer (for the C++ part of the question): The Itanium ABI for C++ prohibits, for historical reasons, using the tail padding of a base subobject of POD type. Note that C++11 does not have such a prohibition. The relevant rule 3.9/2 that allows trivially-copyable types to be copied via their underlying representation explicitly excludes base subobjects.

                  长答案:我会尝试同时处理 C++11 和 C.

                  Long answer: I will try and treat C++11 and C at once.

                  1. S1 的布局必须包含填充,因为 S1::a 必须与 int 对齐,并且数组 S1[N] 由连续分配的 S1 类型的对象组成,每个对象的 a 成员必须如此对齐.
                  2. 在 C++ 中,非基本子对象的可简单复制类型 T 的对象可以被视为 sizeof(T) 字节的数组(即,您可以将指向unsigned char *的对象指针,并将结果作为指向unsigned char[sizeof(T)]的第一个元素的指针,这个数组的值决定了物体).由于 C 中的所有对象都是这种类型,这就解释了 C 和 C++ 的 S2.
                  3. C++ 剩下的有趣案例是:
                  1. The layout of S1 must include padding, since S1::a must be aligned for int, and an array S1[N] consists of contiguously allocated objects of type S1, each of whose a member must be so aligned.
                  2. In C++, objects of a trivially-copyable type T that are not base subobjects can be treated as arrays of sizeof(T) bytes (i.e. you can cast an object pointer to an unsigned char * and treat the result as a pointer to the first element of a unsigned char[sizeof(T)], and the value of this array determines the object). Since all objects in C are of this kind, this explains S2 for C and C++.
                  3. The interesting cases remaining for C++ are:
                  1. 不受上述规则约束的基础子对象(参见 C++11 3.9/2),以及
                  2. 任何非普通可复制类型的对象.

                  对于 3.1,确实存在常见的、流行的基本布局优化",其中编译器将类的数据成员压缩"到基本子对象中.当基类为空时(∞% 大小减少!),这是最引人注目的,但更普遍地适用.但是,当相应的基本类型是 POD 时,我在上面链接的用于 C++ 的 Itanium ABI 以及许多编译器实现的 C++ ABI 禁止这种尾部填充压缩(POD 意味着可简单复制和标准布局).

                  For 3.1, there are indeed common, popular "base layout optimizations" in which compilers "compress" the data members of a class into the base subobjects. This is most striking when the base class is empty (∞% size reduction!), but applies more generally. However, the Itanium ABI for C++ which I linked above and which many compilers implement forbids such tail padding compression when the respective base type is POD (and POD means trivially-copyable and standard-layout).

                  对于 3.2,Itanium ABI 的相同部分适用,尽管我目前不认为 C++11 标准实际上要求任意的、非平凡可复制的 member 对象必须具有与相同类型的完整对象相同的大小.

                  For 3.2 the same part of the Itanium ABI applies, though I don't currently believe that the C++11 standard actually mandates that arbitrary, non-trivially-copyable member objects must have the same size as a complete object of the same type.

                  保留以前的答案以供参考.

                  我相信这是因为 S1 是标准布局,因此出于某种原因,S3S1-子对象保持不变.我不确定标准是否要求这样做.

                  I believe this is because S1 is standard-layout, and so for some reason the S1-subobject of S3 remains untouched. I'm not sure if that's mandated by the standard.

                  然而,如果我们将 S1 变成非标准布局,我们观察到布局优化:

                  However, if we turn S1 into non-standard layout, we observe a layout optimization:

                  struct EB { };
                  
                  struct S1 : EB {   // not standard-layout
                      EB eb;
                      int a;
                      char b;
                  };
                  
                  struct S3 : S1 {
                      char c;
                  };
                  

                  现在 sizeof(S1) == sizeof(S3) == 12 在我的平台上.现场演示.

                  Now sizeof(S1) == sizeof(S3) == 12 on my platform. Live demo.

                  这是一个更简单的例子:

                  struct S1 {
                  private:
                      int a;
                  public:
                      char b;
                  };
                  
                  struct S3 : S1 {
                      char c;
                  };
                  

                  混合访问使 S1 成为非标准布局.(现在 sizeof(S1) == sizeof(S3) == 8.)

                  The mixed access makes S1 non-standard-layout. (Now sizeof(S1) == sizeof(S3) == 8.)

                  更新:定义因素似乎是平凡以及标准布局,即类必须是 POD.以下非 POD 标准布局类是基础布局可优化的:

                  Update: The defining factor seems to be triviality as well as standard-layoutness, i.e. the class must be POD. The following non-POD standard-layout class is base-layout optimizable:

                  struct S1 {
                      ~S1(){}
                      int a;
                      char b;
                  };
                  
                  struct S3 : S1 {
                      char c;
                  };
                  

                  再次sizeof(S1) == sizeof(S3) == 8.演示

                  这篇关于扩展填充结构时,为什么不能在尾部填充中放置额外的字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:可变大小的结构 C++ 下一篇:sizeof(struct) 返回意外值

                  相关文章

                  <i id='2KDRa'><tr id='2KDRa'><dt id='2KDRa'><q id='2KDRa'><span id='2KDRa'><b id='2KDRa'><form id='2KDRa'><ins id='2KDRa'></ins><ul id='2KDRa'></ul><sub id='2KDRa'></sub></form><legend id='2KDRa'></legend><bdo id='2KDRa'><pre id='2KDRa'><center id='2KDRa'></center></pre></bdo></b><th id='2KDRa'></th></span></q></dt></tr></i><div id='2KDRa'><tfoot id='2KDRa'></tfoot><dl id='2KDRa'><fieldset id='2KDRa'></fieldset></dl></div>
                  1. <legend id='2KDRa'><style id='2KDRa'><dir id='2KDRa'><q id='2KDRa'></q></dir></style></legend>
                      <bdo id='2KDRa'></bdo><ul id='2KDRa'></ul>

                    <small id='2KDRa'></small><noframes id='2KDRa'>

                    1. <tfoot id='2KDRa'></tfoot>