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

时间:2016-08-29 08:16:28

标签: c iphone ios-simulator language-lawyer

为什么以下代码在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

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

2 个答案:

答案 0 :(得分:5)

来自C11 standard "6.3.2.3-7"

  

指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未针对引用的类型正确对齐,则行为未定义。 ...

来自C11 standard "J.2"

  在以下情况下,

行为未定义:...

     
      
  • 两种指针类型之间的转换会产生错误对齐的结果(6.3.2.3)。
  •   

强调我的

答案 1 :(得分:2)

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

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