3

可能重复:
未定义、未指定和实现定义的行为

这应该是段错误。为什么不呢。

    #include <string.h>
    #include <stdio.h>

    char str1[] = "Sample string. Sample string. Sample string. Sample string. Sample string. ";
    char str2[2];

    int main ()
    {
      strcpy (str2,str1);
      printf("%s\n", str2);
      return 0;
    }

我正在使用带有以下命令的 gcc 4.4.3 版:

    gcc -std=c99 testString.c -o test

我还尝试将优化设置为 o (-O0)。

4

5 回答 5

8

这应该是段错误

没有理由“应该”出现段错误。代码的行为是未定义的。这并不意味着它一定要崩溃。

于 2012-01-27T17:37:10.600 回答
4

仅当您执行操作系统知道您不应该访问的内存时才会发生分段错误。

因此,可能发生的是操作系统在页面中分配内存(通常在 4KiB 左右)。str2可能与 位于同一页面上str1,并且您没有在页面末尾运行,因此操作系统不会注意到。

这就是未定义行为的问题。任何事情都有可能发生。现在,该程序实际上在您的机器上“工作”。明天,str2可能会放在一个页面的末尾,然后是segfault。或者,您可能会覆盖内存中的其他内容,并产生完全不可预测的结果。

编辑:如何导致段错误:

两种方式。一个仍然是未定义的行为,另一个不是。

int main() {
    *((volatile char *)0) = 42; /* undefined behavior, but normally segfaults */
}

或者以定义的方式进行:

#include <signal.h>

int main() {
    raise(SIGSEGV); /* segfault using defined behavior */
}

编辑:段错误的第三种和第四种方式

这是使用 strcpy 的第一种方法的变体:

#include <string.h>

const char src[] = "hello, world";
int main() {
    strcpy(0, src); /* undefined */
}

而这个变体只会让我崩溃-O0

#include <string.h>

const char src[] = "hello, world";
int main() {
    char too_short[1];
    strcpy(too_short, src); /* smashes stack; undefined */
}
于 2012-01-27T17:40:23.367 回答
2

您的程序写入超出了数组的分配范围,这会导致Undefined Behavior
该程序格式错误,它可能会崩溃,也可能不会。解释可能会也可能不会。

它可能不会崩溃,因为它会覆盖超出数组边界的一些未使用的内存,但一旦该内存的合法所有者尝试访问它,它就会崩溃。

于 2012-01-27T17:35:36.320 回答
1

段错误不是 保证行为。

这是做坏事的一种可能(有时是可能的)结果。
另一个可能的结果是它完全靠运气。
第三种可能的结果是鼻恶魔。

于 2012-01-27T17:42:50.050 回答
0

如果您真的想找出这可能会损坏什么,我建议您查看被覆盖的内存之后会生成一个链接器映射文件,该文件应该会给您一个公平的想法,但这一切都取决于内存中的布局, 甚至可以尝试使用 gdb 运行它来解释它为什么会或不会出现段错误,也就是说,访问冲突中内置检查的粒度(硬件辅助)不能比页面更精细,除非抛出一些软件魔法(即使此页面粒度访问检查可能会发生紧接的下一页确实指向您正在执行的程序的其他内容并且它是一个可写页面),了解 valgrind 的人可以解释它如何能够检测到这种访问违规(也是自由),很可能(我可能对这个解释非常错误,如果我错了,请纠正我!)它使用某种形式的标记或比较来检查是否发生了越界访问。

于 2012-01-27T19:51:46.910 回答