由于一个C字符阵列需要一个空终止,下面的代码打印4个一个 S和一些乱码.
char y[4] = {'a', 'a', 'a', 'a'};
printf("y = %s\n", y);
Run Code Online (Sandbox Code Playgroud)
输出:
y = aaaa?
Run Code Online (Sandbox Code Playgroud)
但是,以下代码不会生成垃圾字符.
char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};
printf("y = %s\n", y);
printf("z = %s\n", z);
Run Code Online (Sandbox Code Playgroud)
输出:
y = aaaa
z = bbb
Run Code Online (Sandbox Code Playgroud)
我知道第四个字符z
是使用null终止符自动初始化的.我猜也是如此,y
并z
在内存中彼此相邻分配.
但是,在这种情况下,C如何正确打印4 a而不是前者?它是否确定下一个字节已经分配给另一个变量,所以它应该再停止打印了?
printf("y = %s\n", y);
在这种情况下,是未定义的行为.换句话说,你很幸运 - 也许你在击中NUL之前打印了一些不可见的字符,也许在阵列之后有一个零因为堆栈对齐,也许星星是正确的.
我通常不会详细说明"它是UB,不要碰",但我觉得很奇怪.
看,这是你的程序:
#include <stdio.h>
int main() {
char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};
printf("y = %s\n", y);
printf("z = %s\n", z);
}
Run Code Online (Sandbox Code Playgroud)
现在我要用我的特殊编译器标志编译它:
$ cc -O3 so15727258.c -o so15727258 -fstack-protector-all -Wall
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ ./so15727258
y = aaaa?>A??0F
z = bbb
Run Code Online (Sandbox Code Playgroud)
哎呀,哈哈,那是垃圾.更好的是,它是随机垃圾,因为堆栈保护器,所以它甚至(简单)不确定.活泉!
还是不相信?特殊的编译器标志对你来说太奇怪了吗?尝试
#include <stdio.h>
int bar() {
char x[4096];
}
int foo() {
char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};
printf("y = %s\n", y);
printf("z = %s\n", z);
}
int main() {
bar();
foo();
}
Run Code Online (Sandbox Code Playgroud)
编译它:
$ cc so15727258.c -o so15727258 -Wall
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ ./so15727258
y = aaaa?????ic?
z = bbb
Run Code Online (Sandbox Code Playgroud)
还是总垃圾!请记住 - 这些例子都是说明性的.当然这是未定义的行为,所以你可能得到一些完全不同的结果,然后回到这里并告诉我"但是XYZ有效".这是未定义行为的定义.
归档时间: |
|
查看次数: |
192 次 |
最近记录: |