使用指针访问内存

问题描述

uint8_t bytes[32];
uint32_t *i = (uint32_t *)&bytes[12];
*i = 0x01020304;
printf("%d\n",bytes[12]);
printf("%d\n",bytes[16]);
printf("%d\n",bytes[20]);
printf("%d\n",bytes[24]);

return 0;

我有以下代码可以打印:

4
208
23
80

有人可以向我解释为什么打印这些值吗?我能理解为什么4个而不是其他。

解决方法

有人可以向我解释为什么打印这些值吗?我能理解为什么4个而不是其他。

数组uint8_t bytes[32];未初始化。写*i = 0x01020304;仅更新项12、13、14、15。假设这是一个本地范围数组,则其余数据包含 indeterminate 值(“垃圾”)。在大多数系统上,读取具有不确定值的变量会产生未指定的结果-您可以获得任何值,并且程序不需要与此保持一致。最常见的是,自从较早执行以来,您获得了一些偶然的废话值,该值恰好位于该存储单元中。

(在某些外来系统上,读取不确定的值可能会导致称为陷阱表示的现象,这意味着可能发生程序崩溃和不确定的行为。)

您看到的4来自系统,使用的是 little endian CPU,数字0x01020304的存储方式类似于[12] = 04,[13] = 03依此类推,最低地址的最低有效字节。其他具有大字节序存储顺序的CPU则以相反的顺序存储,那么您将获得索引[12] = 01。

但是,从uint8_tuint32_t的转换本身就是可疑的:

(uint32_t *)&bytes[12];

此行有两个大的未定义行为问题:

  • 数据可能未对齐(在这种情况下不是),或者不能作为目标类型显示(在有符号整数的情况下不太可能,在其他情况下很有可能)。

  • 这也违反了C类型系统(“严格别名冲突”,高级主题What is the strict aliasing rule?),这意味着编译器可能最终会得出关于存储在特定内存中的内容的错误结论。生成机器代码时的位置。

通常来说,我们不能故意推断一个程序的结果包含未定义的行为,也不能推断一个程序依赖未指定的行为。参见What is undefined behavior and how does it work?