确定 C/C++ 结构与其成员的对齐方式

2024-04-17

如果已知结构成员的对齐方式,是否可以找到结构类型的对齐方式?

Eg. for:

struct S
{
 a_t a;
 b_t b;
 c_t c[];
};

S = max(alignment_of(a),alignment_of(b),alignment_of(c)) 的对齐方式是?

在互联网上搜索我发现“对于结构化类型,其任何元素的最大对齐要求决定了结构的对齐方式”(在每个程序员都应该了解的内存知识 http://people.redhat.com/drepper/cpumemory.pdf)但我在标准中找不到任何类似的内容(更准确地说是最新草案)。


Edited:非常感谢所有的答案,特别是罗伯特·甘布尔(Robert Gamble),他为最初的问题和其他贡献者提供了非常好的答案。

简而言之:

为了确保结构成员的对齐要求,结构的对齐必须至少与其最严格成员的对齐一样严格。

至于确定结构的对齐,提出了一些选项,经过一些研究,我发现:

  • c++ std::tr1::alignment_of
    • 尚未标准,但接近(技术报告 1),应该在 C++0x 中
    • the following restrictions are present in the latest draft: Precondition:T shall be a complete type, a reference type, or an array of unknown bound, but shall not be a function type or (possibly cv-qualified) void.
      • 这意味着我提出的使用 C99 灵活数组的用例将无法工作(这并不奇怪,因为灵活数组不是标准 C++)
    • 在最新的 C++ 草案中,它是根据新关键字 -alignas 定义的(这具有相同的完整类型要求)
    • 在我看来,如果c++标准支持C99灵活数组,则可以放宽要求(结构与灵活数组的对齐不应根据数组元素的数量而改变)
  • c++ boost::alignment_of
    • 主要是tr1的替代品
    • 似乎专门用于 void 并在这种情况下返回 0 (这在 c++ 草案中是禁止的)
    • 开发人员注意:严格来说,您应该只依赖 ALIGNOF(T) 的值作为 T 的真实对齐方式的倍数,尽管实际上它确实在我们所知的所有情况下计算出正确的值。
    • 我不知道这是否适用于灵活的数组,它应该(一般情况下可能不起作用,这解析为我的平台上的编译器固有的,所以我不知道它在一般情况下会如何表现)
  • Andrew Top presented a simple template solution for calculating the alignment in the answers
    • 这似乎非常接近 boost 正在做的事情(如果据我所知,boost 会另外返回对象大小作为对齐方式,如果它小于计算的对齐方式),所以可能同样的通知适用
    • 这适用于灵活的数组
  • use Windbg.exe to find out the alignment of a symbol
    • 不是编译时,特定于编译器,没有测试它
  • using offsetof on the anonymous structure containing the type
    • 查看答案,不可靠,不能用 c++ 非 POD 移植
  • compiler intrinsics, eg. MSVC __alignof
    • 适用于灵活的阵列
    • alignof 关键字位于最新的 C++ 草案中

如果我们想使用“标准”解决方案,我们仅限于 std::tr1::alignment_of,但是如果将 c++ 代码与 c99 的灵活数组混合在一起,那么这将不起作用。

据我所知,只有 1 个解决方案 - 使用旧的 struct hack:

struct S
{
 a_t a;
 b_t b;
 c_t c[1]; // "has" more than 1 member, strictly speaking this is undefined behavior in both c and c++ when used this way
};

在这种情况下(以及所有其他情况),不同的 C 和 C++ 标准以及它们日益增长的差异是不幸的。


另一个有趣的问题是(如果我们无法以可移植的方式找出结构的对齐方式)最严格的对齐要求是什么。我可以找到几个解决方案:

  • boost(内部)使用各种类型的联合并在其上使用 boost::alignment_of
  • the latest c++ draft contains std::aligned_storage
    • The value of default-alignment shall be the most stringent alignment requirement for any C++ object type whose size is no greater than Len
      • so the std::alignment_of< std::aligned_storage<BigEnoughNumber>>::value应该给我们最大的对齐
      • 仅草案,尚未标准(如果有的话),tr1::aligned_storage没有这个属性

任何对此的想法也将不胜感激。

我暂时取消选中已接受的答案,以获得更多关于新子问题的可见性和输入


这里有两个密切相关的概念:

  1. 处理器访问特定对象所需的对齐方式
  2. 编译器实际用于在内存中放置对象的对齐方式

为了确保结构成员的对齐要求,结构的对齐必须至少与其最严格成员的对齐一样严格。我认为标准中没有明确说明这一点,但可以从以下事实推断出来(在标准中单独说明):

  • 结构are允许在其成员之间(以及最后)有填充
  • 数组是not允许元素之间有填充
  • 您可以创建任何结构类型的数组

如果结构的对齐不至少与其每个成员一样严格,则您将无法创建结构数组,因为某些结构成员和某些元素将无法正确对齐。

现在,编译器必须根据其成员的对齐要求确保结构的最小对齐,但它也可以以比所需更严格的方式对齐对象,这通常是出于性能原因而这样做。例如,许多现代处理器允许以任何对齐方式访问 32 位整数,但如果未在 4 字节边界上对齐,则访问速度可能会明显变慢。

没有可移植的方法来确定处理器对任何给定类型强制执行的对齐,因为这不是由语言公开的,尽管编译器显然知道目标处理器的对齐要求,它可以将此信息公开为扩展。

尽管许多编译器可以选择对对齐方式提供一定程度的控制,但也没有可移植的方法(至少在 C 语言中)来确定编译器如何实际对齐对象。

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

确定 C/C++ 结构与其成员的对齐方式 的相关文章

  • 如何将包含 5000 条记录的 Excel 文件插入到 documentDB 中?

    我有一个 Excel 文件 最初约有 200 行 我能够将 Excel 文件转换为数据表 并且所有内容都正确插入到 documentdb 中 Excel 文件现在有 5000 行 在插入 30 40 条记录后不会插入 其余所有行不会插入到
  • 起订量要求?违背了目的?

    是否需要虚拟化您想要模拟的所有属性访问器就违背了模拟的目的 我的意思是 如果我必须修改我的对象并虚拟化我想要模拟的每个访问器 我难道不能继承我的类并自己模拟它吗 你的问题非常有效 但如果你仔细想想 没有其他方法可以模拟课程 如果你采用一个接
  • 将图像文件从网址复制到本地文件夹?

    我有该图像的网址 例如 http testsite com web abc jpg http testsite com web abc jpg 我想将该 URL 复制到 c images 中的本地文件夹中 而且当我将该文件复制到文件夹中时
  • 使用API​​隐藏程序标题栏

    它可以使用 c 和 windows api 删除窗口控制台标题栏 如果是的话如何 请 这个简单的应用程序隐藏并显示其所在控制台的标题栏 它会立即将控制台标题更改为 guid 以查找窗口句柄 然后 它使用 ToggleTitleBar 使用找
  • 为什么这个函数指针赋值在直接赋值时有效,但在使用条件运算符时无效?

    本示例未使用 include 在 MacOS10 14 Eclipse IDE 上编译 使用 g 选项 O0 g3 Wall c fmessage length 0 假设这个变量声明 int fun int 这无法通过 std touppe
  • 访问“if”语句之外的变量

    我怎样才能使insuranceCost以外可用if陈述 if this comboBox5 Text Third Party Fire and Theft double insuranceCost 1 在 if 语句之外定义它 double
  • 找到的程序集的清单定义与程序集引用不匹配

    我试图在 C Windows 窗体应用程序 Visual Studio 2005 中运行一些单元测试 但出现以下错误 System IO FileLoadException 无法加载文件或程序集 实用程序 版本 1 2 0 200 文化 中
  • 如何在编译C代码时禁用警告?

    我正在使用 32 位 Fedora 14 系统 我正在使用编译我的源代码gcc 有谁知道如何在编译c代码时禁用警告 EDIT 是的 我知道 最好的办法是修复这些警告以避免任何未定义 未知的行为 但目前在这里 我第一次编写了巨大的代码 并且在
  • Qt 计算和比较密码哈希

    目前正在 Qt 中为测验程序构建面向 Web 的身份验证服务 据我了解 在数据库中存储用户密码时 必须对其进行隐藏 以防落入坏人之手 流行的方法似乎是添加的过程Salt https en wikipedia org wiki Salt cr
  • 方法“xxx”不能是事件的方法,因为该类派生的类已经定义了该方法

    我有一个代码 public class Layout UserControl protected void DisplayX DisplayClicked object sender DisplayEventArgs e CurrentDi
  • 序列化和反序列化 Visual Studio 解决方案文件 - 或以编程方式编辑?

    我想以编程方式添加和删除项目 解决方案文件夹和其他项目 例如解决方案的资源文件 但我不确定最好的方法是什么 对于那些不知道的人 高度简化 解决方案文件 sln 通常如下所示 Microsoft Visual Studio Solution
  • 手动将 ClientBase 集合类型从 Array[] 更改为 List<>

    我将自己的 WCF 代理与 Client Base 一起使用 我想做一些类似于 svc util 中的 ct 属性的操作 并告诉代理返回 List 集合类型 我不能使用 List 因为实体由 nhibernate 管理 所以我必须使用 IL
  • 您可以在一个 Windows Azure 实例上部署多个 Web 应用程序吗?

    是否可以在一个 windows azure 小型计算实例中运行一堆 Web 应用程序 我正在考虑使用 Azure 作为放置一堆处于开发和非生产状态的项目 Web 应用程序 的地方 有些实际上已经被封存了 但我想在某个地方有一个活跃的实例 我
  • 防止GDB中的PLT(过程链接表)断点

    在最新版本的 GDB 中 在库函数调用上设置断点会导致多个实际断点 调用过程链接表 PLT 实际的函数调用 这意味着当调用库函数时 我们每次都会经历两次中断 在以前的 GDB 版本中 只会创建 2 因此您只能得到一次中断 那么问题来了 是否
  • 错误左值需要作为赋值C++的左操作数

    整个程序基本上只允许用户移动光标 如果用户位于给定的坐标范围 2 2 内 则允许用户键入输入 我刚刚提供了一些我认为足以解决问题的代码 我不知道是什么导致了这个问题 你能解释一下为什么会发生吗 void goToXY int int 创建一
  • 将非算术类型作为参数传递给 cmath 函数是否有效?

    给定以下用户定义类型S具有转换功能double struct S operator double return 1 0 以及以下调用cmath http en cppreference com w cpp header cmath使用类型的
  • 设计 Javascript 前端 <-> C++ 后端通信

    在我最近的将来 我将不得不制作一个具有 C 后端和 Web 前端的系统 要求 目前 我对此了解不多 我认为前端将触发数据传输 而不是后端 所以不需要类似 Comet 的东西 由于在该领域的经验可能很少 我非常感谢您对我所做的设计决策的评论
  • 相当于 C# 中 Java 的“ByteBuffer.putType()”

    我正在尝试通过从 Java 移植代码来格式化 C 中的字节数组 在 Java 中 使用方法 buf putInt value buf putShort buf putDouble 等等 但我不知道如何将其移植到 C 我尝试过 MemoryS
  • 启动画面后主窗口出现在其他窗口后面

    我有一个带有启动屏幕的 Windows 窗体应用程序 当我运行该应用程序时 启动屏幕显示正常 消失并加载应用程序的主窗体 但是 当我加载主窗体时 它出现在包含该应用程序的 Windows 资源管理器目录下 这是运行启动画面然后运行主窗体的代
  • FindAsync 很慢,但是延迟加载很快

    在我的代码中 我曾经使用加载相关实体await FindAsync 希望我能更好地遵守 C 异步指南 var activeTemplate await exec DbContext FormTemplates FindAsync exec

随机推荐