奇怪的行为 c 自愿溢出
strange Behaviour c voluntary overflow
这是代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 10;
int b = 20;
//printf("\n&a value %p", &a);
int* x = &b;
x = x + 1;
*x = 5;
printf("\nb value %d", b);
printf("\na value %d", a);
}
我想用 b 地址覆盖 a 以测试 c 溢出但是当我评论第 5 行(printf 函数)时我不能在 a 中写 5。而如果我打印 a 地址,我可以在 a 中写五个。
为什么?
对不起我的英语,谢谢。
在 x = x + 1;
之后,x
包含一个不属于您的地址。通过执行 *x = 5;
,您正在尝试写入您可能无法访问的某个位置。从而造成UB。没有更多可以推理的了。
发生这种情况的原因是所有普通编译器都将具有自动存储持续时间的对象(在块内声明的对象不是 static
或 extern
)存储在堆栈上。您的编译器将 a
“推”到堆栈上,这意味着它将 a
写入堆栈指针指向的内存位置,然后递减指针。 (递减指针会添加到堆栈中,因为堆栈会朝着内存地址递减的方向增长。堆栈可以朝向另一个方向,但您观察到的行为强烈表明您的系统使用向下增长的共同方向。)然后你的编译器将 b
压入堆栈。所以 b
最终位于 a
.
下面的内存地址
当您获取 b
的地址并添加一个时,会生成 a
所在的内存地址。当您使用该地址分配 5 时,该值被写入 a
所在的位置。
None 这种行为是由 C 标准定义的。这是您使用的特定编译器和编译时使用的开关的结果。
您可能在编译时几乎没有优化。启用优化后,许多编译器会通过删除不必要的步骤(实质上用快捷方式替换它们)来简化代码,这样 20 和 10 就不会实际存储在堆栈中。优化的一个可能结果是打印了“20”和“10”,而你对 *x
的分配没有效果。然而,C 标准并没有说明当您以这种方式使用 *x
时的行为必须是什么,因此结果仅由您使用的特定编译器以及您提供的输入开关决定。
这是代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 10;
int b = 20;
//printf("\n&a value %p", &a);
int* x = &b;
x = x + 1;
*x = 5;
printf("\nb value %d", b);
printf("\na value %d", a);
}
我想用 b 地址覆盖 a 以测试 c 溢出但是当我评论第 5 行(printf 函数)时我不能在 a 中写 5。而如果我打印 a 地址,我可以在 a 中写五个。 为什么? 对不起我的英语,谢谢。
在 x = x + 1;
之后,x
包含一个不属于您的地址。通过执行 *x = 5;
,您正在尝试写入您可能无法访问的某个位置。从而造成UB。没有更多可以推理的了。
发生这种情况的原因是所有普通编译器都将具有自动存储持续时间的对象(在块内声明的对象不是 static
或 extern
)存储在堆栈上。您的编译器将 a
“推”到堆栈上,这意味着它将 a
写入堆栈指针指向的内存位置,然后递减指针。 (递减指针会添加到堆栈中,因为堆栈会朝着内存地址递减的方向增长。堆栈可以朝向另一个方向,但您观察到的行为强烈表明您的系统使用向下增长的共同方向。)然后你的编译器将 b
压入堆栈。所以 b
最终位于 a
.
当您获取 b
的地址并添加一个时,会生成 a
所在的内存地址。当您使用该地址分配 5 时,该值被写入 a
所在的位置。
None 这种行为是由 C 标准定义的。这是您使用的特定编译器和编译时使用的开关的结果。
您可能在编译时几乎没有优化。启用优化后,许多编译器会通过删除不必要的步骤(实质上用快捷方式替换它们)来简化代码,这样 20 和 10 就不会实际存储在堆栈中。优化的一个可能结果是打印了“20”和“10”,而你对 *x
的分配没有效果。然而,C 标准并没有说明当您以这种方式使用 *x
时的行为必须是什么,因此结果仅由您使用的特定编译器以及您提供的输入开关决定。