请考虑以下代码(请注意注释):
#include <iostream>
int main()
{
int x = 1; // <-- Why??/
x += 1;
std::cout << x << std::endl;
}
要编译该程序,我正在使用GNU C ++编译器g++
:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
现在,当针对 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
对于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
在阅读了有关三字母组合的内容之后,我了解到它们在C ++ 17中已被删除,因此如上例所示,被编译器忽略。但是,对于C ++ 11,即使在注释中,它也会被转换!
现在,我可以看到如果Trigraph例如位于字符串中,那会对代码产生怎样的影响。但是,在此示例中,由于它在注释中,因此不应该忽略它吗?
从注释中删除结尾的正斜杠(“ /”)之后,所有警告均消失。我的问题是这里到底发生了什么?为什么输出不同?
答案 0 :(得分:5)
三元组??/
在实际编译发生之前(即在删除注释之前)由编译器转换为\
。
这些行
int x = 1; // <-- Why??/
x += 1;
转换为
int x = 1; // <-- Why\
x += 1;
行尾的反斜杠将下一行追加到该行之后。变成了
int x = 1; // <-- Why x += 1;
将语句x+=1;
移动到注释中,因此它不会被编译。
当您删除尾随的/
时,它不再是三部曲(既然现在只有??
),并且没有什么特别的事情。
答案 1 :(得分:5)
三边形是在代码中插入某些字符的非常古老的方法,可能并非在所有键盘上都可用。有关完整列表,请参见cppreference。
在您的示例中,您意外地创建了三部曲??/
之一,该三部曲被翻译为\
。尾随\
具有特殊含义-它告诉编译器忽略换行符,并将下一行视为当前行的一部分。
您的代码将像这样翻译:
int x = 1; // <-- Why??/
x += 1;
int x = 1; // <-- Why\
x += 1;
int x = 1; // <-- Why x += 1;
这实际上是警告的意思。
Trigraph被解释并更改为\
,即使您使用//
,它也创建了多行注释。
现在,三字母组合在C ++ 11中被贬低,并在C ++ 17中从标准中被删除。 这意味着,在C ++ 11中进行编译时,您的三部曲已翻译,但在C ++ 17中,它被忽略了(编译器向您发送了一条说明,指出您仍然可以启用它们)。
答案 2 :(得分:3)
如果将??/
转换为\
,则??//
将转换为\/
。
或者//
也开始注释,因此三字母组合的应用程序规则首先出现,只有在此之后,编译器才会检查它是否为注释。