c-取消引用指向1字节数组的4字节指针



我有一个程序看起来像这个

#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t arr[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

uint32_t *p = (uint32_t *)&arr[4];

printf("Value of p: %02Xhn", *p);
return 0;
}

正在打印的输出是7060504h,它是

*p = (arr[7] << 24) | (arr[6] << 16) | (arr[5] << 8) | arr[4]; // (1)

我有以下问题:

  1. 为什么arr[7]是MSB而不是arr[4]
  2. 为什么输出是按照(1(而不是(2(计算的
*p = (arr[1] << 24) | (arr[2] << 16) | (arr[3] << 8) | arr[4]; // (2)

为什么arr[7]是MSB而不是arr[4]

C标准规定,在C 2018 6.2.6.1中:"除了位字段,对象由一个或多个字节的连续序列组成,顺序,其编码是显式指定的或实现定义的。">

这意味着C实现可以将对象的字节按其选择和文档的任何顺序放置。您正在使用的实现将低值字节放在低地址,将大值字节放置在大地址。这被称为小端序。(相反的顺序是big-endian。(

为什么按照(1(而不是(2(计算输出?

这个问题不清楚。为什么期望使用数组的元素4、5、6和7的表达式从元素1、2、3和4生成值?

uint32_t *p = (uint32_t *)&arr[4];

使用以这种方式定义的*p的行为不是由C标准定义的。它导致uint8_t的数组被访问,就好像它是uint32_t一样。C 2018 6.5 7说,这是没有定义的。也可能存在误差,因为uint32_t的对准要求可能比uint8_t的要求更严格。

设置uint32_t字节的定义方法是:

uint32_t p;
memcpy(&p, arr, sizeof p); // Include <string.h> to declare memcpy.

然后,由于这个p不是指针,所以用printf("Value of p: %08Xhn", p);打印它。

最新更新