在C中解释反斜杠

Ton*_*moy 5 c escaping slash backslash

任何人都可以解释下面的代码,并请解释反斜杠(\)在这种情况下的作用.什么\',\",\ooo,\ \,\?手段?

#include <stdio.h>
int main(){
    char a = '\010';
    char y = '010';
    printf("%d,%d",a,y);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:8,48

Sha*_*our 5

'\010'八进制 10中的八进制转义序列8十进制的,它将int在调用时被提升为一个,printf以便解释该值.

'010'是一个多字符常量,它的值是实现定义的,如果我们查看C99草案标准部分6.4.4.4 字符常量10段说(强调我的):

[...]包含多个字符(例如,'ab')的整数字符常量的值,或包含未映射到单字节执行字符的字符或转义序列的值是实现定义的.[ ...]

如果你使用的gcc话你会看到至少这个警告:

警告:多字符字符常量[-Wmultichar]

溢出时可能还有这个警告:

警告:隐式常量转换溢出[-Woverflow]

y获得的值更有趣,因为字符常量具有整数值,它不能只取第一个字符,多字符常量必须取数值然后转换为char.clang帮助提供更详细的警告:

警告:从'int'到'char'的隐式转换将值从3158320更改为48 [-Wordstant-conversion]

当前版本的gcc产生相同的值,我们可以从这段简单的代码中看到:

printf("%d\n",'010');
Run Code Online (Sandbox Code Playgroud)

那么它3158320来自哪里?对于gcc至少,如果我们看一下对文档实现定义的行为,它说:

编译器一次评估一个字符的多字符字符常量,将前一个值移动每个目标字符的位数,然后在截断到目标宽度的新字符的位模式中输入字符.最终的位模式为int类型,因此无论单个字符是否有符号都是有符号的(与版本3.1及更早版本的GCC略有不同).如果常量中的字符数多于目标int中的字符数,则编译器会发出警告,并忽略多余的前导字符.

如果我们执行上面的操作(假设8位字符)文档,我们看到:

 48*2^16 + 49*2^8 + 48  = 3158320
 ^         ^
 |         decimal value of ASCII '1'
 decimal value of ASCII '0'
Run Code Online (Sandbox Code Playgroud)

gcc无论是有符号还是无符号,都将转换intchar使用模数2^8,这有效地使我们留下最后一位或.char848


dev*_*ull 5

在第一种情况下,\010被解释为导致的八进制8.

在第二种情况下,返回0(第一个字符010)的ascii值,即48.

如果你有编译器警告,很可能你已经想到了第二个

char y = '010';
Run Code Online (Sandbox Code Playgroud)

靠自己.(gcc会发射-Wmultichar,-Woverflow在这种情况下.)


引用C1X草案,第6.4.4.4节:

整数字符常量具有类型int.包含映射到单字节执行字符的单个字符的整数字符常量的值是解释为整数的映射字符的表示的数值.包含多个字符(例如'ab')的整数字符常量的值,或包含未映射到单字节执行字符的字符或转义序列的值是实现定义的.如果整数字符常量包含单个字符或转义序列,则其值是当char值为单个字符或转义序列的类型的对象转换为类型时生成的值int.


Lih*_*ihO 5

它是一个转义序列,用于删除某些保留字符的含义,例如'或指定一些特殊字符,例如换行符,'\n'或者在这种情况下是具有特定ASCII值的字符:

char a = '\010';
Run Code Online (Sandbox Code Playgroud)

定义八进制ASCII值为10 8的字符,即十进制值8 10.

char y = '010';
Run Code Online (Sandbox Code Playgroud)

定义一个多字节字符,应该分配给宽字符,而不是char.虽然未定义此赋值的行为,但在这种情况下,它很可能会导致存储最后一个字符y