【发布时间】:2015-10-10 03:28:09
【问题描述】:
就像C代码:
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
结果是55,但我不明白如何计算。
我知道'\'后面是八进制数或十六进制数,97 是十六进制数吗?
【问题讨论】:
就像C代码:
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
结果是55,但我不明白如何计算。
我知道'\'后面是八进制数或十六进制数,97 是十六进制数吗?
【问题讨论】:
\ 是八进制转义序列,但 9 不是有效的八进制数字,因此不是将其解释为八进制,而是将其解释为多字符常量 \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 部分中的 C99 标准草案 字符常量 第 10 段说(强调我的):
整数字符常量的类型为 int。整数字符常量的值 包含映射到单字节执行字符的单个字符是 被解释为整数的映射字符表示的数值。 包含多个字符的整数字符常量的值(例如, 'ab'),或包含不映射到单字节的字符或转义序列 执行字符,是实现定义的。
例如gcc 的实现记录在here 中,如下所示:
编译器一次计算一个字符的多字符字符常量,将前一个值左移每个目标字符的位数,然后在截断到宽度的新字符的位模式中进行或运算的目标人物。最终的位模式被赋予 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到\71的转换并不明显。
编辑
我后来意识到真正发生的事情是 \ 正在被删除,所以 \9 -> 9,所以我们真正拥有的是:
c = ((unsigned char)'9')*256 + '7' ;
这似乎更合理,但仍然是武断的,我不清楚为什么这不是一个直截了当的错误。
更新
通过阅读带注释的 C++ 参考手册,我们发现在 Classic C 和旧版本的 C++ 中,当反斜杠后面的字符未定义为转义序列时,它是相等的到字符的数值。 ARM部分2.5.2:
这与经典 C 和 C++ 的早期版本的解释不同,其中黑斜线序列的值后跟源字符集中的字符,如果未定义为转义序列,则等于数值的性格。例如 '\q' 将等于 'q'。
【讨论】:
\9 不是有效的转义,因此编译器会忽略它并且 ascii '7' 是 55。
我不会依赖这种行为,它可能是未定义的。但这就是 55 的来源。
edit:Shafik 指出它不是未定义的,而是已定义的实现。请参阅他的答案以获取参考资料。
【讨论】:
首先,我假设您的代码应该阅读此内容,因为它与您的标题相符。
#include<stdio.h>
int main(void) {
char c = '\97';
printf("%d",c);
return 0;
}
\9 无效,因此我们假设字符实际上是 7。7 是 ascii 55,这是打印出来的答案。
我不确定你想要什么,但\97 不是...
【讨论】:
\9 不是有效的转义序列,因此它可能会退回到普通的 9 字符。
这意味着它与 '97' 相同,这是 undefined 实现定义的(参见 Shafik Yaghmour 的回答)行为(2 个字符不能放入 1 个字符...)。
为避免将来发生此类情况,请考虑在编译器上增加警告。例如,gcc 的最小值应为 -Wall -Wextra -pedantic。
【讨论】: