我有一个程序看起来像这个
#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)
我有以下问题:
- 为什么
arr[7]
是MSB而不是arr[4]
- 为什么输出是按照(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);
打印它。