先用简单的话讲一下什么是trigraph吧,这样不会一上来就是没人看得懂的话,trigraph是三字母词,又叫三连字。
言归正传,总得来说,thrgraph是C/C++ 为了照顾老一辈的"无产阶级革命家"而出现的,当时他们的条件极其艰苦,键盘上缺了很多键,无法输入以下九个字符:
# \ ^ [ ] { } | ~
由此推才出现了 trigraph .
换句话说,就是把上面的每个字符用其他三个字符来代替,替换规则如下:
# | ??= |
\ | ??/ |
^ | ??' |
[ | ??( |
] | ??) |
{ | ??< |
} | ??> |
| | ??! |
~ | ??- |
下面举个例子来说明,下面是一个C++的简单程序:
#include <iostream>
using namespace std;
int main() {
cout << "[]" << endl;
return 0;
}
在当时键盘没有那九个符号的时候,那些程序员们就这么写:
??=include <iostream>
using namespace std;
int main() ??<
cout << "??(??)" << endl;
return 0;
??>
以上内容转自百度上搜到的某个空间看到的,空间名叫"草"...
将 trigraph 替换成对应的字符发生在预处理之前,因此 trigraph 可以在源码中的任何位置都可以用,包括字符串内,函数体开头,预处理指令等。
有人说,如果那我就是用一个字符串常量,其中包含了 "??=" 怎么办?比如说就是要打印两个问号接一个等号,怎么办?很简单,把它拆开写, 为了打印出 "??=",我们把它拆成 "??" "=" 即可,因为 C/C++ 在处理字符串字面值的时候,会把相邻的多个字符串字面值合并成一个,而这个合并操作发生在 trigraph 替换之后,
下面的程序就可以正确的打印出两个问号和一个等号:
#include <iostream>
using namespace std;
int main() {
cout << "??" "=" << endl;
}
实测中,
VC 8 不给任何提示将 trigraph 替换成对应字符,
GCC 4.0.3 则要求加上编译参数 -trigraphs 才会做相应转换。
虽然 GCC 的做法是不符合标准的,但是更加安全。
更详细的情况可以参考标准 2.3。
以下是从c语言参考课程里摘的一段话:
C源程序的源字符集被包含在7位ASCII字符集中,但不是ISO 646-1983Invariant Code Set的子集。三字母(trigraph)序列允许C程序仅使用ISO(国际标准组织) Invariant Code Set编写。三字母是编译器用对应的标点字符替换的三字符序列(以两个问号开头)。你可以在C源文件中使用三字母,该源文件的字符集不能包含某些标点字符的方便图形表示。
一个三字母总是作为单个源字符处理,在第一次转换阶段中,在识别字符串文字和字符常量中的转义字符之前进行三字母的转换。仅识别表1.1中列出的9个三字母,所有其它字符序列不作转换。
字符转义序别\?防止类似三字母的字符序列被误解释(有关转义序列的信息,参见本章后面的“转义序列”)。例如,如果你试图用以下printf语句打印字符串What??!:
printf(“What??!\n");
打印的字符串What|,因为??!是一个三字母,它被|字符所替换。正确打印这个字符串的语句如下:
printf(What?\?!\n");
在这个printf语句中,在第二个问号之前加上一个反斜杠转义字符防止??!作为一个三字母的误解释。