为什么是 "\?" C/C++中的转义序列?

Yu *_*Hao 37 c c++ string gcc escaping

在C/C++中有四个需要转义的特殊非​​字母字符:单引号\',双引号\",反斜杠\\和问号\?.这显然是因为它们具有特殊含义.'对于单个char,"对于字符串文字,\对于转义序列,但为什么是?其中之一?

我今天阅读了教科书中的逃逸序列表,我意识到我以前从未逃脱?过,从未遇到过问题,只是为了确定,我在gcc下进行了测试:

#include <stdio.h>
int main(void)
{
    printf("question mark ? and escaped \?\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和C++版本:

#include <iostream>
int main(void)
{
    std::cout << "question mark ? and escaped \?" << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

两个程序输出: question mark ? and escaped ?

所以我有两个问题:

  1. 为什么是\?转义序列字符之一?
  2. 为什么非逃避?工作正常,甚至没有警告.

在我要问这个问题之前,我自己找到了答案,因为我没有在SO中找到重复,我决定以问答方式发布.

更有趣的事实是,转义\?可以和?其他一些语言一样使用,我在Lua/Ruby中测试过,即使我没有找到这个记录也是如此.

Yu *_*Hao 40

为什么是\?转义序列字符之一?

因为它很特殊,所以答案导致Trigraph,C/C++预处理器将以下三个字符的序列替换为相应的单个字符.(C11§5.2.1.1和C++11§2.3)

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

Trigraph现在几乎没用,主要用于混淆目的,在IOCCC中可以看到一些例子.

默认情况下,gcc不支持三元组,并且如果代码中有三字符,则会发出警告,除非启用了选项-trigraphs3.在-trigraphs选项下,第二个\?在以下示例中很有用:

printf("\?\?!\n");  
Run Code Online (Sandbox Code Playgroud)

输出将是|if ?不被转义.

有关trigraph的更多信息,请参阅Cryptic line"??!??!" 在遗留代码中


为什么非逃避?工作正常,甚至没有警告.

因为?(和双引号")可以由标准表示:

C11§6.4.4.4 字符常数第4节

双引号"和问号?是或者通过它们自身或者通过转义序列可表示\"\?分别的,但单引号'和反斜杠\应分别表示,由转义序列\'\\.

类似于C++:

C++11§2.13.2 字符文字第3节

某些非图形字符,单引号,双引号",问号?,和反斜杠\,可以根据表6中双引号来表示"和问号?,可以被表示为自己或由转义序列\"\?分别,但单引号和反斜杠\应由转义序列来表示\’\\分别.如果反斜杠后面的字符不是指定的字符之一,则行为未定义.转义序列指定单个字符.

  • 如何双引号```由它自己表示?没有转义如何在字符串中间输入双引号? (3认同)
  • 这一行:`例如,除非启用选项-trigraphs,否则默认情况下gcc不支持三元组.根据这些选择,\?在某些情况下是有用的:`是**误导**.似乎即使你不使用`-trigraphs`选项,gcc也会将`??!`解释为`|`. (2认同)
  • @LưuVĩnhPhúc 标准对此并不清楚。我认为 `"` 不能在字符串文字内部使用,但可以在单引号中使用它,如 `'"'` 或 `'\"'`,但 `'''` 无效,必须使用 `' \''`。 (2认同)
  • 我不认为三连词现在"几乎没用".根据我的理解,在生产代码中找到任何使用三字符的努力未能在编译器测试套件之外找到*任何*故意使用,演示三元组如何工作等等.这听起来像是一个更准确(可能更少外交)的陈述"这个功能从来没有真正有用,而且本来就不应该使用该语言". (2认同)