TLDR:诸如此类的东西
char x[] = "some output \06 MORE OUTPUT";
puts(x);
带来意想不到的结果。
所以我有这个代码:
#include <stdio.h>
int main(void)
{
char x[] = "some output \0 MORE OUTPUT";
puts(x);
return 0;
}
并且它打印:“一些输出”,这是预期的,因为
\0
意味着字符串的结尾。但如果我在 \0
之后添加一个数字,结果就会改变。所以代码
#include <stdio.h>
int main(void)
{
char x[] = "some output \06 MORE OUTPUT";
puts(x);
return 0;
}
打印:一些输出♠更多输出
因此,出于某种原因,如果我在
\0
之后添加一个数字,那么 \0
不再被识别为字符串的结尾,而是打印这个 ♠ 符号。
如果我只是将
\0
替换为 \6
,结果是一样的。如果我用其他数字来做,结果是一样的,只是符号不同。
这是为什么呢?这
\6
是什么东西?我在网上找不到任何有关它的信息。它是如何运作的?
\0
实际上除了零字符之外没有特殊含义。按照惯例,我们使用该形式编写空终止符,因为它使语法类似于其他转义序列,如 \n
。
但是
\ <digits>
实际上是所谓的八进制转义序列。任何以 \
开头的字符都会将字符插入到与八进制数对应的字符串中。 06
是 ACK 或 ASCII 中的某些字符,不可打印的字符。 \101
将打印 'A'
等等。
如果转义序列结尾在 C 中没有明确定义,编译器可能会继续读取
\
之后的任何数字,只要它们可用于形成有效字符即可。或者直到它发现另一个转义序列或字符串文字的结尾。
因此
\08
将导致空终止符,因为数字 8
不能是八进制数的一部分。 \10188
将打印 A88
等。并且 \101666
将打印 A666
,因为八进制数 1016 及以上太大而无法形成有效字符,但 101 足够大。
要在空终止符或其他八进制转义序列之后插入字符
'6'
,最简单的方法就是结束字符串文字:
char x[] = "some output \0" "6 MORE OUTPUT"; // string literals will get concatenated into one
puts(x);
char* secret_message = x + 13;
puts(secret_message);
输出:
some output
6 MORE OUTPUT
同样有十六进制转义序列
\x
。