标准布局和尾部填充

2023-12-07

David Hollman 最近在推特上发布了以下示例(我对其进行了稍微简化):

struct FooBeforeBase {
    double d;
    bool b[4];
};

struct FooBefore : FooBeforeBase {
    float value;
};

static_assert(sizeof(FooBefore) > 16);

//----------------------------------------------------

struct FooAfterBase {
protected:
    double d;
public:  
    bool b[4];
};

struct FooAfter : FooAfterBase {
    float value;
};

static_assert(sizeof(FooAfter) == 16);

您可以检查布局在上帝螺栓上叮当作响看到大小改变的原因是FooBefore, 会员value放置在偏移量 16 处(保持 8 的完全对齐)FooBeforeBase)而在FooAfter, 会员value放置在偏移量 12 处(有效地使用FooAfterBase的尾部填充)。

我很清楚FooBeforeBase是标准布局,但是FooAfterBase不是(因为它的非静态数据成员并不都具有相同的访问控制,[class.prop]/3)。但这是关于什么的FooBeforeBase标准布局需要这种填充字节吗?

gcc 和 clang 都重用FooAfterBase的填充,最终为sizeof(FooAfter) == 16。但 MSVC 没有,最终为 24。标准是否有必需的布局,如果没有,为什么 gcc 和 clang 会这样做?


有一些混乱,所以只是澄清一下:

  • FooBeforeBase是标准布局
  • FooBefore is not(它和基类都有非静态数据成员,类似于E in 这个例子)
  • FooAfterBase is not(它具有不同访问权限的非静态数据成员)
  • FooAfter is not(由于上述两个原因)

这个问题的答案不是来自标准,而是来自 Itanium ABI(这就是为什么 gcc 和 clang 有一种行为而 msvc 有其他行为)。 ABI 定义a layout,就本问题而言,其相关部分是:

出于规范内部的目的,我们还指定:

  • dsize(O):数据大小一个对象的大小,是没有尾部填充的 O 的大小。

and

我们忽略 POD 的尾部填充,因为该标准的早期版本不允许我们将其用于其他任何用途,而且它有时允许更快地复制类型。

其中除虚拟基类之外的成员的放置定义为:

从偏移量 dsize(C) 开始,如果需要与基类的 nvalign(D) 对齐或与数据成员的align(D) 对齐,则递增。将 D 放置在此偏移处,除非 [...不相关...]。

术语 POD 已从 C++ 标准中消失,但它意味着标准布局和普通可复制。在这个问题中,FooBeforeBase是一个POD。安腾 ABI 忽略尾部填充 - 因此dsize(FooBeforeBase) is 16.

But FooAfterBase不是 POD(它是可以简单复制的,但它是not标准布局)。结果,尾部填充不会被忽略,所以dsize(FooAfterBase)才 12 岁,而且float可以去那里。

正如 Quuxplusone 在一篇文章中指出的,这会产生有趣的后果相关答案,实现者通常还假设尾部填充不被重用,这对这个示例造成了严重破坏:

#include <algorithm>
#include <stdio.h>

struct A {
    int m_a;
};

struct B : A {
    int m_b1;
    char m_b2;
};

struct C : B {
    short m_c;
};

int main() {
    C c1 { 1, 2, 3, 4 };
    B& b1 = c1;
    B b2 { 5, 6, 7 };

    printf("before operator=: %d\n", int(c1.m_c));  // 4
    b1 = b2;
    printf("after operator=: %d\n", int(c1.m_c));  // 4

    printf("before std::copy: %d\n", int(c1.m_c));  // 4
    std::copy(&b2, &b2 + 1, &b1);
    printf("after std::copy: %d\n", int(c1.m_c));  // 64, or 0, or anything but 4
}

Here, =做正确的事(它不会覆盖B的尾部填充),但是copy()有一个库优化可以减少到memmove()- 它不关心尾部填充,因为它假设它不存在。

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

标准布局和尾部填充 的相关文章

  • 将反序列化方法转换为异步

    我正在尝试使用 Async Await 转换此将对象反序列化为字符串的方法 public static T DeserializeObject
  • CodeLite 配色方案(主题)对于 C 来说很混乱

    我最近将 CodeLite for Linux Debian 更新到版本 14 0 我主要将 CodeLite 用于 C 看起来 IDE 搞乱了颜色主题 这里我有之前 CodeLite 13 0 https i stack imgur co
  • 使用和重载基类的模板成员函数?

    下面 构造Y超载X的成员函数f 两个重载都是模板函数 但采用不同的参数 typename and int 明确指定 struct X template
  • pop() 期间提升 Fibonacci 堆访问冲突

    Context 我目前正在实现某种形式的 A 算法 我决定使用 boost 的斐波那契堆作为底层优先级队列 我的图表是在算法运行时构建的 作为我使用的顶点对象 class Vertex public Vertex double double
  • 信用卡号应该存储为字符串还是整数?

    是啊 只是想想而已 我应该将在我的网站上输入的信用卡号存储为字符串还是整数 我的意思是 它们由数字组成 这让我认为它是一个整数 但我不对它们进行数学运算 所以也许字符串更合适 编辑 所以我必须在加密之前存储在某个时刻输入的数字 我可能应该更
  • 可以作为参数传递给 POST 方法的对象的最大大小

    我有一个带有 POST 方法的 Web API 控制器 如下所示 public class MyController ApiController POST api Scoring public HttpResponseMessage Pos
  • 错误:调用 Configuration.BuildSessionFactory() 时“无法同时获取多个包”;

    升级到 NHibernate 2 1 后 我们收到此错误 QueryException Cannot simultaneously fetch multiple bags NHibernate Loader BasicLoader Post
  • 什么是合适的 NHibernate / Iesi.Collections.Generic.ISet 替代品?

    在最新版本的 Iesi Collections 中缺少 Iesi Collections Generic ISet 似乎有三种选择 链接哈希集 只读集 同步集 Iesi Collections Generic ReadOnlySet 似乎最
  • C++ 局部变量销毁顺序

    C 11 中是否存在局部变量释放的定义顺序 更简洁地说 同一作用域中两个局部变量的析构函数的副作用将以什么顺序变得可见 e g struct X X do something int main X x1 X x2 return 0 Is x
  • main() 是用户定义函数吗? [复制]

    这个问题在这里已经有答案了 程序员does定义内部发生的事情main 毕竟 那么 它应该被视为用户定义的函数吗 C 标准没有用户定义函数的概念 相反 它有一个概念库函数 main 不是库函数 但是 该标准还对其签名提出了一些要求 并且不得重
  • 为什么要在 C 和 C++ 项目中创建 include/ 目录?

    当我处理我的个人 C 和 C 项目时 我通常把file h and file cpp在同一目录中 然后file cpp可以参考file h with a include file h 指示 然而 通常会发现库和其他类型的项目 如 linux
  • 如何重命名 MacOS/X 程序中的程序名称菜单标签?

    我有一个在 MacOS X 下运行的基于 Qt 的 GUI 程序 我希望能够更改该程序的第一个菜单标题的标签 即此屏幕截图中用红色圈出的标签 有没有一种编程方法可以做到这一点 假设不存在基于 Qt 的解决方案 则 Objective C 本
  • iText7 RegexBasedLocationExtractionStrategy 如何获取找到的文本的字体名和字体大小

    我尝试在 C 上使用 iText7 进行文本替换 我只能使用 RegexBasedLocationExtractionStrategy 获取搜索文本的内容和矩形 并且我想获取文本的字体和大小 有什么建议么 谢谢 你可以实施IText提取策略
  • WCF:通用接口的序列化可能吗?

    我正在尝试实现一个服务契约 其中包含一个采用通用接口的方法 并且该通用接口本身被赋予一个接口参数 我用 ServiceKnownType 装饰了服务接口 用常规 KnownType 装饰了服务实现 并用常规 KnownType 装饰了数据契
  • 对双向链表进行排序 C++

    尝试通过遍历列表的循环来完成此操作 在循环中 我将头节点输入到我定义的排序函数中 然后使用 strcmp 来确定节点中的哪个名称是否应该排在前面 它不起作用 因为写得太早了 我通过一次沿着列表一个节点进行线性比较 而不是回去查看第一个节点是
  • C# 中的任意精度小数?

    是否存在任意精度decimal类可用于 C 吗 我见过几个任意精度整数类 但这并不完全相同 您可以使用 J 库java math BigDecimal类 如果已安装 只需添加一个引用即可vjslib me remembers one of
  • 如何在控制台应用程序中创建事件循环/消息管道?

    我想创建一个注册了一些事件的控制台应用程序 问题是这些事件永远不会被触发 在这种特殊情况下Windows 窗体 http en wikipedia org wiki Windows Forms我应该调用的应用程序Application Ru
  • Action 的通用约束未按预期工作

    我无法理解为什么以下代码片段没有给我错误 public void SomeMethod
  • 我使用 difftime 的 c 函数有时会返回 65535

    我有一个函数 使用 difftime 来检测自通信心跳停止以来的时间 以秒为单位 该函数的运行速度可以达到每 50 毫秒一次 该函数似乎可以工作 除了偶尔返回 65535 之外 我可以将执行次数减少到每秒一次 因为 difftime 的返回
  • 在 Outlook 中检索当前电子邮件正文

    在我的 Outlook 插件中 我想在功能区上添加一个按钮 因此当用户单击此按钮时 我想检索当前选定的电子邮件的正文 我有此代码 但它只检索收件箱中的第一封电子邮件 因为索引为 1 Microsoft Office Interop Outl

随机推荐

  • 使用 JavaScript 将秒转换为 HH-MM-SS?

    如何将秒转换为HH MM SS使用 JavaScript 字符串 您可以借助 JavaScript Date 方法在没有任何外部 JavaScript 库的情况下做到这一点 如下所示 const date new Date null dat
  • PostgreSQL Last_value 忽略空值

    我知道已经有人问过这个问题 但为什么下面的解决方案不起作用 我要填value最后一个非空值的排序方式为idx 我所看到的 idx coalesce 1 2 2 4 3 4 5 10 5 rows 我想要的是 idx coalesce 1 2
  • 使用 shell_exec('passwd') 更改用户密码

    我需要能够通过网页 在受控环境中 更改用户的密码 因此 为此 我使用以下代码 我的问题是该脚本没有更改用户 testUser 的密码 我究竟做错了什么 Thanks 另一种选择是使用一个 shell 脚本 比如名为 passwd chang
  • 在 C# 中使用 newtonsoft 查找并返回 JSON 差异?

    我想获得使用 Newtonsoft 进行比较时不匹配的 JSON 部分的列表 我有这个比较代码 JObject xpctJSON JObject Parse expectedJSON JObject actJSON JObject Pars
  • 编译静态版QT + OpenSSL 支持

    我从这里下载了 qt everywhere opensource src 5 8 0 的源文件 https download qt io snapshots qt 5 8 5 8 0 latest src 我想编译它并支持静态版本的 QT
  • 自动重命名视频文件

    我有很多文件想要重命名 手动重命名需要很长时间 它们是视频文件 通常采用以下格式 节目名称 剧集编号 剧集名称 例如 绝命毒师 101 Pilot 我想做的是将 101 部分更改为我自己的约定 S01E01 我认为在一系列节目中 该字符串的
  • 无法在 Windows 中安装 Pylint - python?

    我是Python新手 我在Windows上安装了Python 位于以下目录中C Program Files Python36 我在用vscode当我尝试在 IDE 中运行以下命令时integrated terminal C Program
  • 使用 HTML 和 CSS 在第一个打印页面上显示不同的页眉

    是否可以使用 HTML 和 或 CSS 的任意组合在第一个标题上显示一个标题printed页面然后显示不同的每个后续的标题printed页 我知道关于 media printCSS 标记仅在打印站点时显示某些内容 但这并不能让我在多个页面上
  • 使用 javascript 移动元素

    使用 JavaScript 移动元素的最佳实践是什么 您使用超时或间隔吗 事件定时为 10 毫秒是不好还是会更精确 您是逐像素移动还是总距离的某一部分移动 如果使用间隔 当元素就位时如何停止间隔 我最近两次在 javascript 中看到运
  • Chris Banes 实施 ActionBar-PulltoRefresh、库错误等

    继我之前关于在我的项目中从 github 导入某个库的问题之后 我决定实现一个不同的库 但此时我遇到了很多错误 导入Android Listview通过pull刷新 项目属性错误 与 Google 目前使用 Chris Banes 的 Ac
  • 通过jQuery更改img src:图像不会刷新

    我正在尝试通过 Phonegap Build 应用程序中的 jquery 动态更改 src 如下所示 photo profile attr src fullPath one load function evt console log loa
  • 在带有 extrafont 包的 .eps 图中使用 Arial 时出错

    我在 R 中使用 ggplot2 为出版物生成图形 其中所有图形都需要为 eps 格式 所有字体都需要为 Arial 我一直在关注本指南使用 extrafont 包来做到这一点 据我了解 该行loadfonts device postscr
  • 使用 java 访问嵌套 JSON 对象值

    files f1 png intext A inval 0 inbinary false f2 png intext A inval 0 inbinary true 当f1 png值不固定时如何访问inval的值 即文件名可以是任何名称 它
  • 从 Windows 服务启用/禁用 Aero

    我有一些代码可以在 Vista 中启用 禁用 Windows Aero 服务 并且我想在 Windows 服务中运行它 该代码在独立应用程序中运行 但是当我从服务运行它时 什么也没有发生 不会引发任何错误或异常 我意识到在服务中运行代码与在
  • 使用 ScalaTest 时出现 java.lang.NoSuchFieldError

    我在使用 ScalaTest 时遇到了一个很难调试的错误 奇怪的是 当我的程序没有 Main 对象时 似乎会发生这种情况 但当它有 Main 对象时 却不会发生这种情况 我的代码实际上只是使用带有多态方法的类型类从列表中获取切片 看起来像这
  • 一个用户数据库为多个应用程序数据库提供服务

    我正在管理一个相当大的数据库 该数据库的复杂性和设计都从单个应用程序数据库开始增长 现在计划添加第五个应用程序 该应用程序带有自己的模式和特定数据 我一直在研究 SSO 解决方案 但这并不是我真正想要的 我的目标是拥有一个客户注册 登录和授
  • 使用 Coldfusion SpreadsheetWrite 和 cfscript 创建多个工作表

    我想使用 CF9 SpreadsheetWrite 和 cfscript 创建一个包含两张表的 Excel 文件 就像是 var data spreadsheetNew data var key spreadsheetNew key spr
  • 比较 XML 时如何忽略某些元素?

    我有一条 XML 消息 如下所示
  • MYSQL 未启动(InnoDB:插件初始化因错误通用错误而中止)

    我重新启动了服务器 因为它冻结了 可能是迄今为止我做过的最愚蠢的事情 然后出现了一些内部服务器错误 我很快发现mysql启动失败 service mysql status 我读了mysql错误日志 Pastebin 并开始谷歌搜索 我正在运
  • 标准布局和尾部填充

    David Hollman 最近在推特上发布了以下示例 我对其进行了稍微简化 struct FooBeforeBase double d bool b 4 struct FooBefore FooBeforeBase float value