关于C语言中的'\?'和%%

关于C语言中的'\?'和%%

一、引语

我们知道C/C++中有四个非字母的字符需要用转义字符来表示:单引号 ' , 双引号 " , 反斜杆 \ 和问号 ?

显然这是因为它们本身有特殊的含义,所以要用转义字符来表示他们自己,单引号'用来表示单个字符,双引号"用来表示字符串,反斜杆\是转义字符的标志,那么问号?呢,我们似乎想不出问号有什么特殊含义,它为什么还要用转义字符来表示它本身呢。

我们通过实验可以发现,不管是否使用转义字符,问号?都能准确地输出问号本身。

#include <stdio.h>

int main() {
    printf("question mark ? and escaped \?\n");

    return 0;
}

输出结果是:question mark ? and escaped ?

所以问号转义字符\?有什么存在的必要吗,为什么不用转义字符也能正常输出问号,甚至连一个编译警告都没有?

 

二、trigraph

为什么问号需要转义字符来表示它本身,显然是因为它确实是有特殊含义的。

我们先来了解一个词trigraph,trigraph是三字母词,又叫三连字。这个特性在现在是不受欢迎和极少使用的,但在早年条件艰苦的时候,我们的计算机键盘不像现在可以打出各种字符,所以就用三个字符连起来表示一个打不出的字符,具体如下:

Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
Replacement:      [    ]    {    }    #    \    ^    |    ~

举个例子,下面是一个简单的C语言程序:

#include <stdio.h>

int main() {

    printf("[]");

    return 0;
}

在早年键盘上没有那九个字符的时候,程序员们就这么写:

??=include <stdio.h>

int main() ??<
    printf("??(??)");

    return 0;
??>

将 trigraph 替换成对应的字符发生在预处理之前,因此 trigraph 可以在源码中的任何位置都可以用,包括字符串内,函数体开头,预处理指令等。

实测中,codeblocks的GCC编译器默认不使用trigraph特性,当你代码中出现了以上三字母词时,会给出一个warning。如果有兴趣实验一下这个trigraph特性,可以在菜单栏中点击Settings -- Compiler -- Compiler settings -- Other compiler options,然后添加编译参数-trigraphs,即可使用trigraph特性。

言归正传,显然问号?是trigraph的一个标志,如我们要输出"??("时最好写成"\?\?(",防止编译器将其误解释为一个trigraph。

 

三、C语言标准允许问号?代表它本身

为什么不用转义字符\?也能准确输出?本身,因为C标准允许这么做

C11 §6.4.4.4 Character constants Section 4

The double-quote " and question-mark ? are representable either by themselves or by the escape sequences \" and \?, respectively, but the single-quote ' and the backslash \shall be represented, respectively, by the escape sequences \' and \\.

上面这条标准说明了问号?和双引号"允许代表他们本身的字符,而单引号'和反斜杠\则必须用转义字符来表示他们本身的字符,可能有人会有疑问,在printf中不能单用"来输出双引号"啊,必须要用\",这是因为"在字符串中有特殊含义,不用转义字符就会产生冲突。如果我们输出单个字符putchar('"');则是允许的,不需要写putchar('\"'); 说明"是能代表它本身的。

 

四、关于printf中要用%%来输出一个%,而不是\%

我们知道对于本身有特殊含义的字符,要用转义字符来表示它本身,也知道%在printf中是格式说明符的一个标志,但其他转义字符都是前面加一个反斜杠\,%前面为什么是一个%。

实际上,%%与转义字符无关,它与printf如何处理格式说明符有关,转义字符对所有字符串有效,并在编译时完成,格式说明符(%)仅在一些函数使用,并在运行时使用。简而言之,在字符串或单个字符中,%都能代表它本身,不需要也不能用%%来表示一个%,只在像printf这样使用%作为格式说明符的函数中规定使用%%来明确表示一个%字符。

posted @ 2018-08-02 14:39  _kangkang  阅读(6117)  评论(0编辑  收藏  举报