我知道当您写入不属于您的内存部分时,会发生中止陷阱 6
,但我在进行 K&R 练习时发现了一些有趣的事情。
/* strcat: copies t to the end of s */
void _strcat(char *s, char *t) {
while (*s != '\0') {
s++;
}
while ((*s++ = *t++) != '\0') { }
}
#include <stdio.h>
int main() {
char s[7] = "hello, ";
char *t = "world";
_strcat(s, t);
printf("%s\n", s);
return 0;
}
感兴趣的部分是char s[7] = "hello, "
。
当数组大小为 7 时,"hello, "
, Abort trap 6
的确切长度不会被打印,即使_strcat
添加超出内存初始化部分的字符。
8 - 12(含)之间的任何数字都会产生中止陷阱 6
,而 >= 13 的数字都可以。
因此出现两个问题:
- 为什么
char s[12] = "hello, "
不行,而7
可以?似乎尾部的'\0'
需要一个大小为13
的数组,但为什么 7 可以呢?不应该是8吗? - 为什么
7
可以呢?大小 8-12 包含"hello, "
就像大小为 7 的字符数组一样,并且写入超出了其原始数组大小,但7
却逃脱了它,而其他人则没有't。
最佳答案
您必须阅读机器代码才能弄清楚这一点。正如 Jonathan Leffler 所说,这是未定义的行为。
这可能取决于编译器以及它如何在内存中布局。不要求大小为 7 的数组获得实际的 7 个字节。它可能决定将其填充到 16,以获得更好的堆栈布局。或者它可能会将其放置在不同的位置,因此后面有一个零和一些额外的空间,而较大的数组会获得不同的位置。
或者,如果您在优化的情况下进行编译,编译器可能会将大小为 7 的循环展开为“正确”代码,从而简化为简单的 puts("hello, world");
但无法内联一个更大的循环。
出于好奇,我做了一个小实验,在 Linux 上使用 GCC 时,答案是在 64 位模式下它总是可以工作,因为 8 字节 char *t
指针中有足够的空间来存储“世界”
。
在 32 位模式下,正如您所描述的那样,它会失败,因为它会覆盖返回堆栈。但是 7 可以处理垃圾数据,因为它在超过返回值之前找不到零,然后它“附加”到开放堆栈空间中。打印结果类似于 hello, ��#m�?��world
关于C `Abort trap: 6` 仅在某些条件下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45602754/