【问题标题】:Why doesn't this code cause a segfault?为什么这段代码不会导致段错误?
【发布时间】:2013-05-07 17:30:56
【问题描述】:

为什么没有这个段错误?

#include <stdio.h>
int main()
{
    int i;
    int arr[] = {1, 2, 3, 4};

    for(i=0;i<8;i++)
    {
        arr[i] = i;
        printf(" %d", arr[i]);
    }

    printf("\n");

    return 0;
}

但当我在 for 循环中将 8 替换为 9 时,它确实如此。

注意:我在 32 位 crunchbang linux 上试用它

【问题讨论】:

  • 读取数组末尾是未定义的行为。未定义的行为可以是任何东西;它不一定必须进行段错误。
  • 纯属运气。它确实打印了一些垃圾号码,不是吗?
  • 另一个过于本地化的骑手... :'(

标签: c segmentation-fault


【解决方案1】:

从技术上讲,这个程序的结果是 undefined behavior,这意味着绝对不能保证这个程序可以做什么。原则上,它可以格式化您的硬盘驱动器,通过电子邮件向您所有的朋友发送讨厌的消息,让您的计算机着火,或者变得有知觉并奴役人类。

在这种情况下,当 n = 8 时的未定义行为碰巧没有做任何坏事,而当 n = 9 时的未定义行为会导致段错误。两者都是程序完全允许的行为,但完全不能保证可移植。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    @templatetypedef 是对的;他打败了我的答案。未定义的行为并不一定意味着段错误。

    但我想提供一些推测,为什么它会出现 n=9 而不是 8 的段错误。通常,像 int iint arr[] 这样的变量驻留在 stack 上,它会向下增长。所以,i 可能位于地址0x4000,如果它是一个 4 字节的int,那么arr[0] 位于0x4004arr[1] 位于0x4008,以此类推。在这种情况下,编译器很可能已经为arr 分配了16 个字节,并且它可能使用0x4014 以下的地址(arr 之后的第一个字节,即arr[5] 的地址)。但是除了您手动声明的变量之外,堆栈上通常还有其他东西。例如,printf 调用的参数可能在堆栈上,并且可能还有其他簿记信息。因此,如果arr[9] 与编译器用于其他用途的堆栈位置一致,您将无意中破坏该信息,这可能导致段错误。

    或者,如果arr[8] 位于从操作系统分配的堆栈帧的底部,那么您的操作系统将配置您的处理器以拒绝执行任何指令以从与 @ 重合的地址加载或存储值987654338@。我认为这种情况不太可能发生,因为堆栈大小通常为 4KB 左右,对于这么短的程序,您应该离分配堆栈的末尾很远。

    【讨论】:

    • 虽然@templatetypedef 正确地说明了未定义的行为,但我正在寻找这样的分析。在循环中执行时, arr 应该在堆栈的顶部。所以它不能腐蚀任何其他成员。 printf 和任何其他簿记的参数将转到更高的地址,例如在调用 printf 时基于编译器的 arr[5] 或 arr[9] 或更高的地址。它可能会覆盖 arr[5] 的某些值。但这不应该影响 printf 的执行。从 printf 返回时,arr 再次位于堆栈顶部。
    【解决方案3】:

    templatetypedef 答案是正确的,这是一种未定义行为的情况(这并不像您想象的那么罕见),但我想补充一点:

    9*sizeof(int) 不是 2 的幂。当编译器分配内存时,它们通常以两个字节的幂进行分配,以防止 heap 出现碎片。

    您可能想知道为什么它不分配 4*sizeof(int) 因为这正是您所要求的。我不确定,但可能是编译器分配了几个额外的字节,或者它具有为数组分配的最小内存量。这取决于编译器和您编译代码时使用的选项。

    尝试在没有优化的情况下运行您的代码(命令行上的 -O0),它可能会分配您需要的确切内存量并为 i>=4 分配段错误。

    我可能是错的,我不确定 C 编译器在堆或堆栈中分配静态数组。

    【讨论】:

    • 你确定这个数组是在堆中分配的吗?我假设以这种方式声明的数组将分配在堆栈上。
    • @templatetypedef 局部变量,包括固定大小的数组,例如arr,通常在 C/C++ 中分配在堆栈上。
    猜你喜欢
    • 2011-03-16
    • 2017-08-18
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多