考虑以下代码(注意注释):
#include <iostream>
int main()
{
int x = 1; // <-- Why??/
x += 1;
std::cout << x << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
要编译这个程序,我使用的是GNU C++编译器g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
Run Code Online (Sandbox Code Playgroud)
现在,在为C++ 11和C++ 17编译时,我会得到不同的结果(和警告).
对于C++ 11 g++ -std=c++11 trigraph.cpp -Wall,:
trigraph.cpp:5:26: warning: trigraph ??/ converted to \ [-Wtrigraphs]
int x = 1; // <-- Why??/
trigraph.cpp:5:16: warning: multi-line comment [-Wcomment]
int x = 1; // <-- Why??/
^
$ ./a.out
1
Run Code Online (Sandbox Code Playgroud)
对于C++ 17 g++ -std=c++17 trigraph.cpp -Wall:
trigraph.cpp:5:26: warning: trigraph ??/ ignored, use -trigraphs to enable [-Wtrigraphs]
int x = 1; // <-- Why??/
$ ./a.out
2
Run Code Online (Sandbox Code Playgroud)
在阅读了有关三字母的一些内容之后,我理解它们已在C++ 17中被删除,因此被编译器忽略,如上例所示.但是,在C++ 11的情况下,即使它在评论中它被转换了!
现在,我可以看到,如果三字符在例如字符串中,那将如何影响代码.但是,在这个例子中,它不应该被忽略,因为它在评论中?
从注释中删除尾随正斜杠("/")后,所有警告都消失了.我的问题是这里究竟发生了什么?为什么输出不同?
??/编译器\在实际编译发生之前(即删除注释之前)将三字符转换为.
所以这些线
int x = 1; // <-- Why??/
x += 1;
Run Code Online (Sandbox Code Playgroud)
转换为
int x = 1; // <-- Why\
x += 1;
Run Code Online (Sandbox Code Playgroud)
行末尾的反斜杠会将下一行附加到它.所以它变成了
int x = 1; // <-- Why x += 1;
Run Code Online (Sandbox Code Playgroud)
这会将语句移动x+=1;到注释中,因此不会编译.
当你删除尾/随时,它不再是一个三角形(现在仅仅是它??),并没有什么特别的事情发生.
Trigraphs是将某些字符插入代码的非常古老的方式,这些代码可能并非在所有键盘上都可用.有关完整列表,请参阅cppreference.
在您的示例中,您意外地创建了一个三元组??/,它被翻译成\.尾随\具有特殊含义 - 它告诉编译器忽略换行并将下一行视为当前行的一部分.
您的代码将被翻译为:
int x = 1; // <-- Why??/
x += 1;
int x = 1; // <-- Why\
x += 1;
int x = 1; // <-- Why x += 1;
Run Code Online (Sandbox Code Playgroud)
这就是警告实际意味着什么.Trigraph被解释并变成了\,它创建了一个多行注释,即使你使用过//.
现在,三元组在C++ 11中被删除,并在C++ 17中从标准中删除.这意味着,在C++ 11中编译时,你的三字图被翻译了,但是在C++ 17中它被忽略了(编译器发给你的是一个你仍然可以启用它们的注释).