【问题标题】:Why doesn't the following code produce a segmentation fault? [duplicate]为什么以下代码不会产生分段错误? [复制]
【发布时间】:2013-04-08 04:43:22
【问题描述】:
#include <iostream>
using namespace std;

int a[4];
int main(){
    int b=7;
    cout<<a[b]<<endl;
    return 0;
}

我试图访问未分配的内存。所以我希望输出是分段错误,而不是输出是一些垃圾值。

后来我将“b”增加到 1000,现在输出是“分段错误”。这种行为是否有特定原因?

我正在使用 gcc-4.3.2 编译器。

【问题讨论】:

  • 其未定义的行为。据你所知,它可能会产生纽约下水道老鼠合唱“一”的合唱。有关详细信息,请参阅 this answer 或此论坛上的许多其他人。
  • 如果你未定义的行为导致我的扬声器出现热点问题,我会把你扔出窗外。
  • 实际发生的情况是编译器将分段错误邮寄给您的母亲,她确切地知道它们是什么,但对您的爱太深而无法表露。

标签: c++ arrays segmentation-fault


【解决方案1】:
如果您尝试访问不存在的内存地址(进程的地址空间之外),则可能会抛出

A segmentation fault

a[7] 在这种情况下可能不在其可访问空间之外,但a[1000] 肯定是。但即使是前者也会在你最意想不到的时候爆炸;)

【讨论】:

  • a[1000] 也不一定在进程的虚拟内存之外(尽管在这种情况下它是)。这取决于您的操作系统上如何实现内存分配。
【解决方案2】:

仅当您访问操作系统不允许您访问的内存时才会发生分段错误。

但是,您可以访问虽然不是您期望的,但已授予您的内存,例如指向堆栈中较早或较晚的内存地址。但这不是你可以依赖的东西,因为本地存储的变量如何放置在堆栈上是由编译器根据会发生变化的神秘优化来决定的——从调试到发布,随着代码的变化等等。

但是,如果您看到类似的内容,“为什么访问这个变量会给我带来垃圾,但总是同样的垃圾?”你可能无意中偷看了你不应该偷看的堆栈部分。

【讨论】:

  • a 不在此处的堆栈中。
【解决方案3】:

这是未定义的行为,所以任何事情都可能发生,你无法判断。检查 this(对于 C++)以了解未定义行为、未指定行为和实现定义行为之间的区别。

附件 J 中的 C - **ISO C9899** 清楚地谈到了这一点。

编辑
C++ - N3485 ISO/IEC in section 1.9.2 ,1.9.3 , 1.9.4 讨论了上述行为。

【讨论】:

  • 你不应该引用C++ standard吗?
  • @AnishRam OP 将其标记为 CC++。在我为 C++ 提供的链接中,已经提到了对标准的引用(所以我重申)。但是对于 C 没有提到,所以我明确提到了它。
  • 不管标签,代码都是C++。
【解决方案4】:

越界访问是未定义的行为。它可以访问进程空间中的任意内存。如果访问的内存未分配或不在进程地址空间中(可能在内核中),那么您的程序将因分段错误而崩溃。在这种情况下,故障将帮助您识别问题,如果幸运的话会崩溃,否则它可能会被忽视,并且稍后会在程序损坏内存中出现一些错误,然后难以跟踪。 a[1000] 未分配的概率更高,因此崩溃。内存按页分配。

【讨论】:

    【解决方案5】:

    未定义的行为不需要引起段错误。考虑int i = INT_MAX + 1; 的另一个通常不会导致段错误的未定义行为示例。

    【讨论】:

      猜你喜欢
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多