c - uint32_t 和 uint8_t[4] 的 C union 会在小端架构上始终以相同的方式映射吗?

标签 c endianness

uint32_t 和 uint8_t[4] 的 C union 会在小端架构上始终以相同的方式映射吗?

例如与

union {
    uint32_t double_word;
    uint8_t octets[4];
} u;

u.double_word = 0x12345678;

总是导致:

u.octets[0] == 0x78
u.octets[1] == 0x56
u.octets[2] == 0x34
u.octets[3] == 0x12

或者这是未定义的行为?

最佳答案

TL;DR:是的,代码没问题。

如前所述,它包含取决于字节顺序的实现定义的行为,但除此之外,行为定义明确且代码可移植(在小端机器之间)。


详细答案:

有一点很重要,数组的分配顺序是有保证的,C11 6.2.5/20:

An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.

这意味着 4 个 uint8_t 的数组保证遵循 uint32_t 的分配顺序,这在小端系统上意味着最低有效字节在前。

理论上,编译器可以自由地在 union 末尾添加任何填充 (C11 6.7.2.1/17),但这不应影响数据表示。如果您想迂腐地防止这种情况 - 或者更相关地,您希望防止以后添加更多成员时出现问题 - 您可以添加编译时断言:

typedef union {
    uint32_t double_word;
    uint8_t octets[4];
} u;

_Static_assert(sizeof(u) == sizeof(uint32_t), "union u: Padding detected");

关于 uintn_t 类型的表示,它保证是 2 的补码(在有符号类型的情况下),没有填充位 (C11 7.20.1.1)。

最后,关于是否允许通过 union 进行“类型双关”或未定义行为的问题,这在 C11 6.5.2.3 中指定得有点模糊:

A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,95) and is an lvalue if the first expression is an lvalue.

(非规范性)注释 95 提供的澄清:

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

并且由于我们已经排除了填充位,因此陷阱表示不是问题。

关于c - uint32_t 和 uint8_t[4] 的 C union 会在小端架构上始终以相同的方式映射吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49627802/

相关文章:

c - 使用 SDCC (Little Endian) 编译器时这个算法有什么问题?

c# - BitConverter 类中 IsLittleEndian 的用例是什么?

c - fread 和 endianness : will fread(pointer, sizeof(some),1,file pointer) 有相同的结果吗?

objective-c - *变量名和变量名有什么区别

c - 如何在Windows中用C获取文件夹大小?

c - 使用 htons 确定字节顺序

c++ - 这段代码是字节序安全的吗?

c - 函数声明 : K&R vs ANSI

c - 为 malloc 创建的二维数组赋值

c - 是否可以记录所有执行的信息以供以后重播?