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

2024-01-25

让我们考虑一下结构:

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。这意味着编译器将它们构造为:

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

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


简短回答(对于问题的 C++ 部分): The 适用于 C++ 的安腾 ABI https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pod由于历史原因,禁止使用 POD 类型的基础子对象的尾部填充。注意C++11没有这样的禁止。相关规则 3.9/2 允许通过其底层表示复制普通可复制类型,明确排除基本子对象。


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

  1. 的布局S1必须包括填充,因为S1::a必须对齐int,和一个数组S1[N]由连续分配的类型对象组成S1,其中每个a成员必须如此对齐。
  2. 在 C++ 中,可简单复制类型的对象T不是基本子对象的可以被视为数组sizeof(T)字节(即,您可以将对象指针强制转换为unsigned char *并将结果视为指向 a 的第一个元素的指针unsigned char[sizeof(T)],并且该数组的值决定了对象)。由于 C 中的所有对象都是这种类型,这解释了S2对于 C 和 C++。
  3. The interesting cases remaining for C++ are:
    1. 基本子对象,不受上述规则的约束(参见 C++11 3.9/2),以及
    2. 任何不属于普通可复制类型的对象。

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

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


之前的回答留作参考。

我相信这是因为S1是标准布局,因此出于某种原因S1- 的子对象S3保持不变。我不确定标准是否强制这样做。

然而,如果我们转向S1对于非标准布局,我们观察布局优化:

struct EB { };

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

struct S3 : S1 {
    char c;
};

Now sizeof(S1) == sizeof(S3) == 12在我的平台上。现场演示 http://ideone.com/g733I0.

这是一个更简单的例子 http://ideone.com/qceEYj:

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

struct S3 : S1 {
    char c;
};

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

Update:决定性因素似乎是琐碎以及标准布局,即类必须是 POD。以下非 POD 标准布局类是可优化基本布局的:

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

struct S3 : S1 {
    char c;
};

Again sizeof(S1) == sizeof(S3) == 8. Demo http://ideone.com/xLrj8s

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当扩展填充结构时,为什么不能在尾部填充中放置额外的字段? 的相关文章

  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • 如何使用MemoryCache代替Timer来触发一个方法?

    以下方法通过等待已运行操作的结果来处理并发请求 对数据的请求可能会使用相同 不同的凭据同时出现 对于每组唯一的凭据 最多可以有一个GetCurrentInternal呼叫正在进行中 当准备就绪时 该呼叫的结果将返回给所有排队的服务员 pri
  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 向 Nhibernate 发出 SQL 查询

    如何将此 SQL 查询发送给 Nhibernate SELECT Customer name FROM Company INNER JOIN Customer ON Company CompanyId Customer CompanyId
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 如何从 .resx 文件条目获取注释

    资源文件中的字符串有名称 值和注释 The ResXResourceReader类让我可以访问名称和值 有办法看评论吗 你应该能够得到Comment via ResXDataNode class http msdn microsoft co
  • 存储来自其他程序的事件

    我想将其他应用程序的事件存储在我自己的应用程序中 事件示例 打开 最小化 Word 或打开文件时 这样的事可能吗 运行程序 http msdn microsoft com en us library ms813609 aspx and 打开
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • Linq-to-entities,在一个查询中获取结果+行数

    我已经看到了有关此事的多个问题 但它们已经有 2 年 或更长 的历史了 所以我想知道这方面是否有任何变化 基本思想是填充网格视图并创建自定义分页 所以 我还需要结果和行数 在 SQL 中 这将类似于 SELECT COUNT id Id N
  • 如何使用 Word Automation 获取页面范围

    如何使用办公自动化找到 Microsoft Word 中第 n 页的范围 似乎没有 getPageRange n 函数 并且不清楚它们是如何划分的 这就是您从 VBA 执行此操作的方法 转换为 Matlab COM 调用应该相当简单 Pub
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐