c/c++语言开发共享为什么在这种特定情况下在堆栈上分配大元素不会失败?

在C中在堆栈上分配int和大数组时,程序执行时没有错误。 但是,如果我事先在堆栈上初始化变量,则会发生段错误(可能是因为大型数组超出了堆栈大小)。 如果在声明数组后初始化变量,这对我来说是有意义的。 是什么导致这种行为,记忆明智?

我的印象是,只需在堆栈上声明一个变量,就会分配所需的空间,导致在分配非常大的数据类型时立即崩溃。

我怀疑它与编译器优化它有关,但它没有意义,考虑到我在第二个例子中也没有改变foo

我正在使用gcc 7.2.0进行编译, 没有设置任何标志 。 在Ubuntu 17.10上执行。

这运行没有错误:

 int main(){ int i; unsigned char foo [1024*1024*1024]; return 0; } 

这会立即崩溃:

 int main(){ int i = 0; unsigned char foo [1024*1024*1024]; return 0; } 

有人能告诉我这里发生了什么吗?

    注意:以下是实现细节。 C标准不包括此内容。

    崩溃不是由分配空间引起的。 崩溃是由于写入不可写的页面或从不可读的页面读取而导致的。

    您可以看到声明实际上不需要读取或写入任何内存,不一定:

     int i; 

    但如果它已初始化,则必须写入值:

     int i = 0; 

    这会触发崩溃。 请注意,确切的行为取决于您使用的编译器和您拥有的优化设置。 不同的编译器将以不同的方式分配变量,优化编译器通常会完全从函数中删除ifoo ,因为它们不是必需的。 某些编译器还会在某些配置下将变量初始化为垃圾值,以帮助调试。

    分配堆栈空间只需要更改堆栈指针,这是一个寄存器。 如果分配的堆栈空间过多,堆栈指针将指向无效的内存区域,程序在尝试读取或写入这些地址时会发生段错误。 大多数操作系统都有“保护页面”,因此有效内存不会放在堆栈旁边,以确保程序在大多数情况下成功崩溃。

    以下是Godbolt的一些输出:

     main: push rbp mov rbp, rsp sub rsp, 1073741720 ; allocate space for locals mov DWORD PTR [rbp-4], 0 ; initialize i = 0 mov eax, 0 ; return value = 0 leave ret 

    请注意,此版本不会崩溃,因为i被放置在堆栈的顶部(向下增长)。 如果i被放置在堆栈的底部,这可能会崩溃。 编译器可以按任何顺序自由地将变量放在堆栈中,因此它是否真的崩溃将在很大程度上取决于您使用的特定编译器。

    您还可以更清楚地看到分配不会崩溃的原因:

     ; Just an integer subtraction. Why would it crash? sub rsp 1073741720 

      以上就是c/c++开发分享为什么在这种特定情况下在堆栈上分配大元素不会失败?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/560191.html

      (0)
      上一篇 2021年1月27日
      下一篇 2021年1月27日

      精彩推荐