就像C代码:</p>
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
结果是55
,但我不明白如何计算。我知道'\'后面是八进制数或十六进制数,97
是十六进制数吗?
\
是八进制转义序列,但9
不是有效的八进制数字,因此不是将其解释为八进制,而是将其解释为多字符常量 a \9
,1
其值由实现定义。没有任何警告标志gcc
默认提供以下警告:
warning: unknown escape sequence: '\9' [enabled by default]
warning: multi-character character constant [-Wmultichar]
warning: overflow in implicit constant conversion [-Woverflow]
6.4.4.4
字符常量第10节中的 C99 草案标准说(强调我的):
整数字符常量的类型为 int。包含映射到单字节执行字符的单个字符的整数字符常量的值是被解释为整数的映射字符表示的数值。 包含多个字符(例如,'ab')或包含不映射到单字节执行字符的字符或转义序列的整数字符常量的值是实现定义的。
例如gcc
实现记录在这里,如下所示:
编译器一次计算一个字符的多字符字符常量,将前一个值左移每个目标字符的位数,然后在截断到目标宽度的新字符的位模式中进行或运算特点。最终的位模式被赋予 int 类型,因此是有符号的,无论单个字符是否有符号(与 GCC 3.1 和更早版本略有不同)。如果常量中的字符多于目标 int 中的字符数,编译器会发出警告,并且忽略多余的前导字符。
例如,对于具有 8 位字符的目标,“ab”将被解释为“(int) ((unsigned char) 'a' * 256 + (unsigned char) 'b')',而 '\234a' 则为'(int) ((unsigned char) '\234' * 256 + (unsigned char) 'a')'。
据我所知,这被解释为:
char c = ((unsigned char)'\71')*256 + '7' ;
这导致55
, 这与上面的多字符常量实现一致,尽管\9
to的翻译\71
并不明显。
编辑
后来我意识到真正发生的事情是\
正在被丢弃等等\9 -> 9
,所以我们真正拥有的是:
c = ((unsigned char)'9')*256 + '7' ;
这似乎更合理,但仍然是任意的,我不清楚为什么这不是一个直截了当的错误。
更新
通过阅读带注释的 C++ 参考手册,我们发现在经典 C和旧版本的 C++ 中,当反斜杠后跟字符未定义为转义序列时,它等于字符的数值。ARM部分2.5.2
:
这与经典 C 和 C++ 的早期版本的解释不同,其中源字符集中后跟字符的黑斜线序列的值(如果未定义为转义序列)等于字符的数值. 例如 '\q' 将等于 'q'。
\9 不是有效的转义,因此编译器会忽略它并且 ascii '7' 是 55。
我不会依赖这种行为,它可能是未定义的。但这就是 55 的来源。
编辑:Shafik 指出它不是未定义的,它是定义的实现。请参阅他的答案以获取参考资料。
首先,我将假设您的代码应该阅读此内容,因为它与您的标题相匹配。
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
\9
无效,因此我们假设字符实际上是 7。7
是 ascii 55,这是打印出来的答案。
我不确定你想要什么,但\97
不是...
\9
不是有效的转义序列,因此很可能会退回到普通9
字符。
这意味着它与未定义的实现定义(参见 Shafik Yaghmour 的回答)行为相同'97'
(2个字符不能放入 1 个字符中......)。
为避免将来出现此类情况,请考虑在编译器上启动警告。例如, 的最小值gcc
应该是-Wall -Wextra -pedantic
。