为什么这个 uint32_t 转换在 iPhone 模拟器和 iPhone 设备上表现不同?

Why does this uint32_t cast behave differently on iPhone simulator and iPhone device?

为什么以下代码在 iPhone 模拟器和设备上表现不同?我 运行 intel macbook pro 上的模拟器,设备是 iPhone 5(型号 MD297KS/A)。

代码:

uint8_t original = 23;
uint8_t * pointerToOriginal = &original;
uint32_t * casted = (uint32_t *)pointerToOriginal;
printf("original: %u\ncasted: %u\n", original, *casted);

模拟器上运行时的输出:

original: 23
casted: 23

设备上 运行 时的输出:

original: 23
casted: 2755278871

我假设转换会导致转换的整数中包含垃圾数据,因此设备输出对我来说有意义,但是 为什么整数不受引入的额外数据的影响在模拟器上投射?

来自C11 standard "6.3.2.3-7"

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...

来自C11 standard "J.2"

The behavior is undefined in the following circumstances: ...

  • Conversion between two pointer types produces a result that is incorrectly aligned (6.3.2.3).

强调我的

首先你的代码会导致未定义的行为。 但为了清楚起见,我将尝试解释发生了什么。

original 存储在堆栈中。因此,当您获取指向 original 的指针时,您将获得指向堆栈内存中长度为 8 位的区域的指针(此信息仅适用于编译器)。像这样:

  byte 0     byte 1    byte 2    byte 3
  [00010111][????????][????????][????????]

假设堆栈从地址 0 开始。 所以 pointerToOriginal 将指向地址 0 处的字节。编译器知道 pointerToOriginal 指向 8 位值(因为它的类型)。因此,当取消引用时,它将从地址 0 开始准确读取 1 个字节。 但是,当将 uint8_t* 转换为 uint32_t* 时,您实际上强制编译器读取 4 个字节而不是 1 个字节。因此您最终将读取 4 个字节,其中 3 个字节将成为垃圾。 在模拟器上,内存区域看起来像是填满了零。所以堆栈看起来像这样:

  byte 0     byte 1    byte 2    byte 3
  [00010111][00000000][00000000][00000000]

当您取消引用 casted 时,您将得到 23。但在真机上它只会包含垃圾。

上面的插图没有解释更高级的东西 - Big and Little Endian