注释中的三连字符,在c ++ 11中转换,在c ++ 17中被忽略

时间:2018-11-15 09:00:49

标签: c++ c++11 c++17

请考虑以下代码(请注意注释):

#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例如位于字符串中,那会对代码产生怎样的影响。但是,在此示例中,由于它在注释中,因此不应该忽略它吗?

从注释中删除结尾的正斜杠(“ /”)之后,所有警告均消失。我的问题是这里到底发生了什么?为什么输出不同?

3 个答案:

答案 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)

如果将??/转换为\,则??//将转换为\/

或者//也开始注释,因此三字母组合的应用程序规则首先出现,只有在此之后,编译器才会检查它是否为注释。