【问题标题】:Stack 8MiB, then why this code "almost" works?堆栈 8MiB,那么为什么这段代码“几乎”有效?
【发布时间】:2019-08-22 17:55:27
【问题描述】:

我到处阅读。
stack8MB,这就是为什么您应该使用指针来存储 heap 中的内容。

好吧,在我的机器上,下面的代码适用于 11MB 的字符,但不适用于 12MB。
我的char c[Nc] array 存储在所谓的 heap 中吗?

#include <stdio.h>

int main()
{
    int Nc = 1024*1024;  // megabyte

    Nc = Nc * 11;  // works
    //Nc = Nc * 12;  // Segmentation fault (core dumped)

    char c[Nc];

    c[0] = 'A';
    c[Nc-1] = 'Z';

    printf("%dmb\n", Nc/1024/1024);

    printf("%c-%c\n", c[0], c[Nc-1]);

    return 0;
}

有什么解释吗?
我只是“用户”而不是程序员。

【问题讨论】:

  • 而且前提“我在每个地方都阅读。堆栈只有 8mb”根本不正确。这仅适用于非常具体的配置。
  • 溢出堆栈是未定义的行为,所以它没有崩溃的事实并不意味着它没有溢出。
  • (a) 默认堆栈大小在某些系统上为 8 MiB,而在其他系统上则不同。您没有告诉我们您使用的是什么系统,因此我们无法知道您系统的大小。它可能是 12 MiB。 (b) 默认堆栈大小是可变的。 (c) 编译器可能会观察到您的程序没有使用所有数组并优化您的程序,以便它实际上根本不会创建数组。您没有告诉我们您正在使用什么编译器或编译开关,所以我们不知道编译器对您的程序做了什么。
  • (d) 到目前为止可能会溢出堆栈,您的程序进入由于其他原因映射的不同内存部分,因此c[Nc-1] = 'Z';实际上是在写入并破坏程序中的其他数据。
  • 堆栈有 8MB 不要相信“无处不在”的所有内容。 我的 char c[Nc] 数组存储在所谓的堆中吗不,不是。

标签: c pointers segmentation-fault heap-memory stack-memory


【解决方案1】:

看起来你正在编译你的程序,至少做了一些优化。当我在 GCC 或 Clang 上使用 -O0 以外的任何内容编译您的代码时,编译器会优化 char 数组的创建。 (Godbolt link)

如果您使用-fsanitize=undefined 编译您的程序,它会将其视为未定义行为。

将这么大的数组放在堆栈上通常被认为是不好的做法。大对象应该在堆上静态分配或分配。操作系统将其默认堆栈分配设置为大多数程序不需要担心的级别,这不是保证。作为程序员,您有责任确保您的程序有足够的堆栈空间来运行。如果需要获取或检查堆栈空间量,可以使用getrlimit()setrlimit()。请参阅man getrlimit 了解更多信息。

【讨论】:

  • gobolt 链接中的数组刚刚优化,因为值是预先知道的。无需访问内存。没有理由崩溃。只需添加extern int nc[Nc - 1-n] = 'Z'; 即可看到:godbolt.org/z/LoV27m
猜你喜欢
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2013-12-17
  • 2015-07-02
  • 1970-01-01
相关资源
最近更新 更多