【问题标题】:Are C unions never padded at the beginning?C 联合从一开始就没有填充吗?
【发布时间】:2017-10-18 17:23:38
【问题描述】:

C99 标准中是否保证联合只会像结构一样在末尾被填充?与此相关的是,联合的地址是否总是等于其任何可能成员的地址?

【问题讨论】:

  • 懒得写答案了,不过就在这里:port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15.Read p15 and p17
  • 如果有 'padding at the beginning',那不就是联合体不在那个位置吗?
  • 请务必阅读第 16 段。它明确提到在联合的开头不能有填充。

标签: c c99


【解决方案1】:
  1. 是的。正如您所注意到的,结构永远不会有前导填充。联合的地址总是引用联合的任何组件的第一个元素(使用适当的强制转换),因此联合的开头也不能有任何填充。

  2. 是的。适当地转换,联合的地址也是一个指向联合内任何元素的指针。

ISO/IEC 9899:2011

6.7.2.12 结构和联合说明符

¶15 在结构对象中,非位域成员和位域所在的单元 驻留的地址按照声明的顺序增加。一个指针 结构对象,经过适当转换,指向它的初始成员(或者如果该成员是 位域,然后到它所在的单元),反之亦然。可能有未命名的 在结构对象内填充,但不在其开头。

¶16 联合体的大小足以容纳其最大的成员。的值 大多数成员可以随时存储在联合对象中。一个指针 适当转换的联合对象指向其每个成员(或者如果成员是位域, 然后到它所在的单元),反之亦然。

¶17 结构或联合的末尾可能有未命名的填充。

【讨论】:

    【解决方案2】:

    标准做出以下保证:

    6.7.2.11-4:一个指向联合对象的指针,经过适当转换,指向它的每个成员(或者如果一个成员是位域,则指向它所在的单元)

    这意味着联合的开头不能有填充。

    【讨论】:

    • 为什么?实现可以在每个联合类型的开头引入固定填充(例如,4 个字节),然后每次将指针从/到指向联合类型的指针转​​换为其他类型时添加/减去此偏移量。这样就满足了上述要求。
    • @AnT 我的理解不同:因为任何指向void* 的指针的转换都是合适的转换,所以表达式(void*)&myUnion(*void)&myUnion.union_member 需要产生相同的结果,这意味着如果存在在 union 的所有成员前面偏移,那么 union 本身的地址必须被填充相同的量,这与地址本身被填充量调整相同。
    【解决方案3】:

    语言规范不直接保证它。但是它说

    一个指向联合对象的指针,经过适当的转换,指向它的每个成员(或者如果一个成员是位域,则指向它所在的单元),反之亦然。

    请注意,C 语言中的指针转换绝不意味着在转换过程中会保留指针的数值(实际地址)。这意味着从技术上讲,可以满足这个要求,并且在并集开始时仍然有填充。

    但是,没有理由将它放在那里。而且,很明显,无意引入这种可能性。特别是如果您考虑到语言规范明确指出结构的开头没有填充。

    【讨论】:

    • C89 的作者没有努力禁止编译器可能做的每一件愚蠢的事情,他们在基本原理中指出,一个实现有可能符合标准,但质量却很差,以至于没用。不幸的是,假设如果标准不禁止编译器做某事,任何依赖于编译器的容忍的代码都应该被视为“有缺陷的”,并且应该鼓励编译器这样做,如果它可以改善不依赖于这种宽容的代码行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 2010-09-16
    • 1970-01-01
    • 2020-03-14
    • 2014-06-07
    • 2011-07-18
    • 2017-03-14
    相关资源
    最近更新 更多