int在C中在堆栈上分配一个大型数组时,程序执行时没有错误.但是,如果我事先在堆栈上初始化变量,则会发生段错误(可能是因为大型数组超出了堆栈大小).如果在声明数组后初始化变量,这对我来说是有意义的.是什么导致这种行为,记忆明智?
我的印象是,只需在堆栈上声明一个变量,就会分配所需的空间,导致在分配非常大的数据类型时立即崩溃.
我怀疑它与编译器优化它有关,但它没有意义,考虑到我foo在第二个例子中也没有改变.
我正在使用gcc 7.2.0进行编译,没有设置任何标志.在Ubuntu 17.10上执行.
这运行没有错误:
int main(){
int i;
unsigned char foo [1024*1024*1024];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这会立即崩溃:
int main(){
int i = 0;
unsigned char foo [1024*1024*1024];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人能告诉我这里发生了什么吗?
C标准定义了许多下限/上限(转换限制),并强制实现应满足每个转换.为什么没有为数组大小定义这样的最小限制?以下程序将编译正常并可能产生运行时错误/段错误,并将调用未定义的行为.
int main()
{
int a[99999999];
int i;
for(i=0;i<99999999;i++)
a[i]=i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可能的原因可能是在自动存储上分配了本地数组,它取决于分配的堆栈帧的大小.但为什么不像C定义的其他限制那样达到最小限度?
让我们忘记上面提到的未定义的情况.考虑以下:
int main()
{
int a[10];
int i;
for(i=0;i<10;i++)
a[i]=i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在上面,是什么让我保证本地数组(尽管非常小)将按预期工作,并且不会因分配失败而导致未定义的行为?
虽然这种小型阵列的分配不太可能在任何现代系统上失败.但是C标准没有定义满足要求,编译器也没有(至少GCC没有)报告分配失败.只有运行时错误/未定义的行为才有可能.困难的部分是没有人能够判断任意大小的数组是否会因分配失败而导致未定义的行为.
请注意,我知道我可以使用动态数组(通过malloc和朋友)来实现此目的,并可以更好地控制分配失败.我更感兴趣的是为什么没有为本地数组定义这样的限制.此外,全局数组将存储在静态存储中,并将增加编译器可以处理的可执行文件大小.
考虑到C中函数内部的局部变量一旦被调用就会被压入堆栈(在压入传递给函数的变量之后),在堆栈缓冲区溢出之前,所述变量的数量是否有限制?或者该限制仅由确定的主机拥有的 RAM 量决定?
我尝试通过创建一个 4,6gb .C 文件来测试这一点,其中包含一个函数,该函数声明了 25000*13 个变量并将其初始化为 0。该函数在内部调用,main()但它编译得很好(使用 -O0)并且没有'崩溃。