【问题标题】:Will the alignment of variables in a C union be the same on all systems?C 联合中的变量对齐方式在所有系统上都相同吗?
【发布时间】:2018-08-02 23:11:22
【问题描述】:

考虑以下联合:

typedef union {
    struct { // Anonymous struct
        int red;
        int green;
        int blue;
    };
    int colorChannels[3];
} Color;

不管这段代码在哪个系统上编译或执行,匿名结构中的字段是否总是与 colorChannels 中的索引对齐?

也就是说,规范是否要求myColor.colorChannels[0]的内存地址与myColor.red的地址相同?

另外,如果将代码编译为 C++ 而不是 C,答案会有所不同吗?

请注意,我询问的是联合中的每个元素都具有相同类型/大小的特定情况(即在这种情况下为 int

【问题讨论】:

  • 答案是“通常,但不是必须的”。您可能想要添加一个静态断言。请注意,在 C++ 中,像这样通过联合进行双关语是未定义的行为。
  • 没有。而且很难理解为什么您会关心他们是否这样做,除非您将这种对齐方式用于一些非常不便携的转换滑稽动作。
  • 注意:允许编译器在成员之间添加填充,例如支持有利于处理器寻址的对齐。
  • @EKW 这不是在 C++ 中实现这一点的方法。
  • 那你为什么把它标记为C++?我刚刚删除了它。

标签: c memory struct unions


【解决方案1】:

不管这段代码在哪个系统上编译或执行,匿名结构中的字段是否总是与 colorChannels 中的索引对齐?

不一定。该实现可以在struct 的各个变量之间添加字节“填充”。 “填充”只是以实现定义的方式插入到struct 的变量之间或末尾的内存定义中的额外内存字节。如果发生这种情况,那么您的整数数组将不会与 struct 的内存布局对齐(除非填充仅位于 struct 的末尾,可能)。内存中struct 中变量的顺序在不同的实现中应该是一致的(因为变量a 后面跟着b,然后是内存中的c),但是,同样,之间的字节填充仍然可以在那里(例如,a 在内存中后跟b,但在ab 之间有填充,因此它们在内存中不是紧挨着的)。

对于像 gcc 这样的编译器,there are ways to modify how it handles padding。这可以帮助保证 struct 将与您的整数数组在内存中对齐,但这可能会导致下游的其他内存问题。

也就是说,规范是否要求myColor.colorChannels[0]的内存地址与myColor.red的地址相同?

如果structredgreenblue 之间没有填充,则colorChannels 的索引将与内存中的每个变量匹配。

【讨论】:

  • 虽然从语言律师的角度来看是正确的;考虑到数组不能有填充但仍然必须正确对齐整数,因此结构选择不同的包装将是非常令人惊讶。另一方面,这是一个可能在 C 中有效但在 C++ 中完全禁止的技巧,因此不是最好的使用方法。
【解决方案2】:

C 标准对此不做任何保证,但它可能在任何存在的实际系统上都是正确的。

我建议在代码中添加编译时检查,以便万一有一些系统添加了填充,你会得到一个编译错误,你可以在当时处理:

_Static_assert( sizeof(Color) == 3 * sizeof(int),  "We're on a weird system boys." );

注意。 _Static_assert 是在 C11 中添加的,在此之前你可以使用一些 hack as described here

【讨论】:

  • 有趣。我不知道_Static_assert。感谢您的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
相关资源
最近更新 更多