【问题标题】:Why am I not getting a segfault error with this simple code?为什么这个简单的代码没有出现段错误?
【发布时间】:2017-06-05 22:57:14
【问题描述】:

当我访问数组外部的项目时,我必须显示一个错误(没有为它创建我自己的函数)。所以我只是认为有必要从数组中访问值来触发段错误,但是这段代码根本不会崩溃:

int main(){
    int tab[4];
    printf("%d", tab[7]);
}

为什么我在执行此操作时不会收到错误消息?

【问题讨论】:

  • 欢迎来到undefined behavior的精彩世界
  • 如果您使用的是 GCC 或 Clang,请尝试使用 -fsanitize=address 进行编译和链接。

标签: c arrays pointers segmentation-fault undefined-behavior


【解决方案1】:

当您调用undefined behavior 时,任何事情都可能发生。你的程序可能会崩溃,它可能会显示奇怪的结果,或者它可能看起来工作正常。

此外,进行看似无关的更改(例如添加未使用的局部变量或简单调用 printf)可能会改变未定义行为的表现方式。

当我运行这个程序时,它完成并打印了 63。如果我将引用的索引从 7 更改为 7000,我会得到一个段错误。

简而言之,仅仅因为程序可以崩溃并不意味着它

【讨论】:

  • 另外,相反,如果一个程序没有(立即)崩溃并不意味着它是正确的。
  • @RadLexus 对。这属于它可能看起来可以正常工作。
【解决方案2】:

因为当你做规范不允许的事情时的行为是"undefined"。而且因为在 C 中不需要边界检查。你很“幸运”。

int tab[4]; 表示为堆栈上的 4 个整数分配内存。 tab 只是内存地址的数字。它不知道它指向什么或分配了多少空间。

printf("%d", tab[7]); 表示打印出tab 的第 8 个元素。所以编译器会...

  • tab 设置为 1000(例如)表示内存地址 1000。
  • tab 表示int 的列表,因此每个元素将是sizeof(int),可能是4 或8 个字节。假设是 8。
  • 因此tab[7] 表示从内存位置 (7 * 8) + 1000 = 1056 开始读取,再读取 8 个字节。所以它的读数是 1056 到 1063。

就是这样。程序本身没有边界检查。硬件或操作系统可能会进行边界检查以防止一个进程读取任意内存,请查看protected memory,但 C 不需要任何内容​​。

所以tab[7] 忠实地复制了 1056 到 1063 中的任何垃圾。

你可以写一个小程序来看看这个。

int main(){
  int tab[4];
  printf("sizeof(int): %zu\n", sizeof(int));
  printf("tab: %d\n", tab);
  printf("&tab[7]: %d\n", &tab[7]);

  /* Note: tab must be cast to an integer else C will do pointer
     math on it. `7 + tab` gives the same result. */
  printf("(7 * sizeof(int)) + (int)tab: %d\n", (7 * sizeof(int)) + (int)tab);
  printf("7 + tab: %d\n", 7 + tab);
}

确切的结果会有所不同,但您会看到 &tab[7] 只是对 tab 进行的一些数学运算,以确定要检查的内存地址。

$ ./test
sizeof(int): 4
tab: 1595446448
&tab[7]: 1595446476
(7 * sizeof(int)) + (int)tab: 1595446476
7 + tab: 1595446476

1595446476 - 1595446448 是 28。7 * 4 是 28。

【讨论】:

    【解决方案3】:

    C 中的数组只是一个指向内存块的指针,在本例中,该内存块的起点为tab[0] 的任意位置。当然,您已经设置了4 的界限,但如果您超过了该界限,您只需访问超过该内存块的随机值。 (即它可能打印出奇怪数字的原因)。

    【讨论】:

      猜你喜欢
      • 2018-02-23
      • 2012-03-25
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      相关资源
      最近更新 更多