http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html 这个页面说传递的局部变量和参数是在堆栈上分配的,所以我尝试了:
#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2
typedef struct {
int a[A][A];
} st;
void fun(st s){}
void main()
{
st s;
//fun(s);
}
编译并运行后未报告任何错误。但是当我取消注释//fun(s)
时,然后被捕获了SIGSEGV。有谁能说出原因?
答案 0 :(得分:11)
本地变量在哪里分配?堆或堆?
此页面表示传递的局部变量和参数在堆栈上分配
完全。
但是当我取消注释// fun(s)时,然后SIGSEGV被捕获了。有谁能说出原因?
堆栈上的内存比堆上的内存更有限¹。您在堆栈上分配2000000x2000000数组,然后将其传递给函数。这很可能超过可用的堆栈空间,导致分段错误。
当函数调用被注释掉时,为什么不发生分段错误。首先,正如Jonathan Leffer所指出的那样,编译器可能会完全优化s
,因为它没有被使用。但即使它没有,你可能也不会得到段错误,因为在堆栈上分配内存只是意味着增加堆栈指针。在大多数实现中,它本身永远不会导致分段错误。只有在您尝试访问已分配的内存并且系统意识到您超出了堆栈的边界(并且在整个内存中也是如此)时,才会发生分段错误。
¹虽然在这种情况下并没有什么不同,因为正如slugonamission指出的那样,数组占用了16TB,因此也会超过堆上的可用内存。
答案 1 :(得分:2)
此外,这是一个很好的例子,为什么你只是按值传递一个函数参数,通常你通过引用传递参数:
#include <stdio.h>
#include <stdlib.h>
#define A 2000000
#define B 2
typedef struct {
int a[A][A];
} st;
void fun(st *s){}
void main()
{
st s;
fun(&s);
}
我认为它根本不会运行,因为它需要堆栈上的4TB内存。由于编译器转储的未使用的//fun(s)
变量并且在运行时根本没有声明,因此它在代码中使用s
进行编译和运行。