【发布时间】:2013-12-19 22:51:07
【问题描述】:
在下面定义的两个函数中,它都尝试在堆栈中分配 10M 的内存。但是分段错误只发生在第二种情况而不是第一种情况下,我试图理解为什么会这样。
函数定义1:
a(int *i)
{
char iptr[50000000];
*i = 1;
}
函数定义2:
a()
{
char c;
char iptr[5000000];
printf("&c = 0x%lx, iptr = 0x%x ... ", &c, iptr);
fflush(stdout);
c = iptr[0];
printf("ok\n");
}
根据我的理解,如果局部变量未动态分配内存,则存储在程序的堆栈部分中。所以我想,在编译期间,编译器本身会检查变量是否适合堆栈。
因此,如果上述情况属实,那么在这两种情况下都应该发生分段错误(即在情况 1 中也是如此)。
我从中选择的网站 (http://web.eecs.utk.edu/courses/spring2012/cs360/360/notes/Memory/lecture.html) 指出,当代码尝试将 iptr 压入堆栈以进行 printf 调用时,段错误发生在 a 的函数 2 中。这是因为堆栈指针指向 void。 如果我们没有在堆栈指针处引用任何东西,我们的程序应该可以运行。
我需要帮助来理解最后的陈述以及我之前对此的疑问。
【问题讨论】:
-
你确定
iptr在第一种情况下没有被优化吗?你不使用它......关于“我们没有在堆栈指针上引用任何东西”的陈述只是说在堆栈上分配大量内存可能不会导致崩溃(因为“分配”通常包括只是将堆栈指针增加分配大小),但尝试使用堆栈会导致崩溃,因为它超过了实际保留堆栈空间的末尾。 -
编译器可以随意放置变量,但不能保证局部变量不会被隐式堆分配。唯一的要求是编译器清理它们。
-
我在Error accessing pointers when succesfully allocated array is too big中解释过,基本上它会调整堆栈指针,但如果它没有实际尝试使用它没有问题。
-
@ShafikYaghmour:感谢您指出这一点。但是这种变量到堆栈的映射是在编译时完成的,在这两种情况下都应该发生段错误,对吗??即使在第一种情况下没有访问试验但仍然完成映射......
-
@AadityaGavandalkar 在堆栈上至少为
gcc分配x86将只是堆栈指针的sub,它不需要越界内存访问。这当然取决于具体的实现,但它很可能解释了您所看到的行为,但在不同平台上的工作方式可能不同,而且这不是您应该回复的行为。
标签: c++ c memory-management segmentation-fault