gpt4 book ai didi

c - 为什么要更改数组大小值来操作十进制字节?

转载 作者:行者123 更新时间:2023-11-30 16:49:49 25 4
gpt4 key购买 nike

这是来自 CMU 计算机系统类(class)。在以下示例中:

 typedef struct { 
int a[2];
double d; } struct_t;

double fun(int i) {
volatile struct_t s;
s.d = 3.14;
s.a[i] = 1073741824; /* Possibly out of bounds */
return s.d; }
fun(0)  ➙ 3.14 
fun(1) ➙ 3.14
fun(2) ➙ 3.1399998664856
fun(3) ➙ 2.00000061035156
fun(4) ➙ 3.14
fun(6) ➙ Segmentation fault

教授解释说,访问 fun(2) 会操作 double d 的字节。但是,我没有得到:(a) 为什么它操作以 fun(2) 开头的双字节,(b) 每个字节操作与 fun(2) ➙ 3.1399998664856fun(3) ➙ 2.00000061035156 等直到 fun(6),以及 (c) 为什么它在 fun (6) 处恰好达到临界状态)?有关我的问题的更多引用,请参阅 here幻灯片8和9。另外,幻灯片上有一个解释图,我看不懂。如果您能花一些时间进行解释,我们将不胜感激。

最佳答案

幻灯片 9 上的图表表示调用 fun 时的本地内存。每行代表 4 个字节(从右到左列出),内存地址随着向下而减少。如果您要以这种格式列出地址 0, 1, 2, ...,它将如下所示:

|...
+--+--+--+--+
|11|10| 9| 8|
+--+--+--+--+
| 7| 6| 5| 4|
+--+--+--+--+
| 3| 2| 1| 0|
+--+--+--+--+

幻灯片 9 上的图表显示了 s(struct_t 类型的变量)在内存中的布局方式。该系统使用 4 字节 int 和 8 字节 double 。因此,s.a[0] 占用 4 个字节(图中的第 0 行),s.a[1] 占用另外 4 个字节(第 1 行),s.d 8 个字节(第 2 行和第 3 行)。

该函数访问s.a[i]。编译器将其转换为采用 s.a 起始地址并向其添加 i*4 字节以到达所选元素的代码。在图中,这对应于从第 0 行开始向上 i 行。只要 i 实际上是数组中的有效索引(在示例中:01,如 a 只有 2 个元素)。

但是如果i更大,那么代码最终会访问内存的其他部分。 s.a[2](图中的第 2 行)引用属于 s.d 一部分的内存,因此覆盖它会破坏存储在那里的值(对于 s.a[3 也是如此) ])。确切的结果值取决于所使用的浮点格式的内部结构(可能是 IEEE 754)。 (我对此并不熟悉,所以我不知道如何准确地解释这些位以获得 3.1399998664856。)

s.a[4] 显然并不重要,因为覆盖它没有任何明显的效果。但是覆盖 s.a[6] 崩溃了,这表明我们破坏了一些重要的东西。这可能是返回地址,即保存的位置,它告诉 fun 完成后跳转到哪里。通过覆盖它,我们有趣跳转到无效内存。

要确认这一点(并找出为什么索引 6 特别会破坏事情),您必须查看编译器生成的代码。没有通用的答案,因为这取决于相关编译器、优化级别、运行的系统等。

但是,在 C 中向本地数组写入越界会在某些时候破坏返回地址是很常见的。这是因为编译器几乎普遍使用堆栈来实现函数调用和本地(“自动”)存储,因此堆栈包含混合的本地变量和返回地址。

关于c - 为什么要更改数组大小值来操作十进制字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42453581/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com