134

根据 C++'03 标准 2.3/1:

在进行任何其他处理之前,每次出现以下三个字符序列(“三字符序列”)中的一个,都将替换为表 1 中指示的单个字符。

----------------------------------------------------------------------------
| trigraph | replacement | trigraph | replacement | trigraph | replacement |
----------------------------------------------------------------------------
| ??=      | #           | ??(      | [           | ??<      | {           |
| ??/      | \           | ??)      | ]           | ??>      | }           |
| ??’      | ˆ           | ??!      | |           | ??-      | ˜           |
----------------------------------------------------------------------------

在现实生活中,这意味着代码printf( "What??!\n" );将导致打印What|,因为??!它是一个被字符替换的三元组序列|

我的问题是使用三元组的目的是什么?使用三元组有什么实际优势吗?

UPD:在回答中提到一些欧洲键盘没有所有的标点符号,所以非美国程序员必须在日常生活中使用三元组?

UPD2:Visual Studio 2010 默认关闭三元组支持。

4

9 回答 9

103

这个问题(关于密切相关的有向图)有答案。

归结为 ISO 646 字符集没有 C 语法的所有字符,因此有些系统的键盘和显示器无法处理这些字符(尽管我认为这些字符非常罕见如今)。

通常,您不需要使用它们,但您需要确切了解它们以了解您遇到的问题。三元组是 ' ?' 字符具有转义序列的原因:

'\?'

因此,可以避免示例问题的几种方法是:

 printf( "What?\?!\n" ); 

 printf( "What?" "?!\n" ); 

但是你必须记住当你输入两个'?你可能会开始一个三元组的字符(这肯定不是我在想的事情)。

在实践中,三合字母和二合字母是我在日常工作中完全不用担心的事情。但是您应该注意它们,因为每隔几年您就会遇到与它们相关的错误(并且您将在一天的剩余时间里诅咒它们的存在)。如果可以将编译器配置为在遇到三合字母或二合字母时发出警告(或错误),那就太好了,这样我就可以知道我有一些我应该有意识地处理的事情。

并且为了完整性,有向图的危险性要小得多,因为它们被处理为标记,因此字符串文字中的有向图不会被解释为有向图。

要获得有关 C/C++ 程序中标点符号的各种乐趣的良好教育(包括一个三字错误,这肯定会让我大吃一惊),请查看Herb Sutter 的 GOTW #86 文章


附录:

看起来 GCC 默认不会处理(并且会警告)三元组。其他一些编译器可以选择关闭三字符支持(例如 IBM 的)。Microsoft 开始在 VS2008 中支持必须显式启用(使用 -Wall 或其他东西)的警告(C4837)。

于 2009-08-05T17:23:30.627 回答
28

今天的孩子们!:-)

是的,国外的设备,比如 IBM 3270 终端。如果我记得的话,3270 没有花括号!如果您想在 IBM 小型/大型机上编写 C,您必须对每个块边界使用可悲的三元组。幸运的是,我只需要用 C 编写软件来模拟一些 IBM 小型机设施,而不是真正在 System/36上编写 C 软件。

查看“P”键旁边:

键盘

嗯。很难说。“回车”旁边有一个额外的按钮,我可能会把它倒过来:也许是“[”/“]”对丢失了。无论如何,如果你不得不写 C,这个键盘会让你很伤心。

此外,这些终端显示 EBCDIC,IBM 的“本机”大型机字符集,而不是 ASCII(感谢 Pavel Minaev 的提醒)。

另一方面,就像 GNU C 指南所说:“你不需要这种脑损伤。” gcc 编译器默认禁用此“功能”。

于 2009-08-05T17:37:01.897 回答
22

来自The C++ Programming Language特别版,第 829 页

ASCII 特殊字符[]{}|\占据 ISO 指定为字母的字符集位置。在大多数欧洲国家 ISO-646 字符集中,这些位置被英文字母表中没有的字母占据。

提供了一组三元组,以允许使用真正标准的最小字符集以可移植的方式表达国家字符。这对于程序的交换很有用,但它不会使人们更容易阅读程序。自然,这个问题的长期解决方案是让 C++ 程序员获得能够很好地支持他们的母语和 C++ 的设备。不幸的是,这对某些人来说似乎是不可行的,并且引入新设备可能是一个令人沮丧的缓慢过程。

于 2009-08-05T17:19:42.757 回答
15

它们用于缺少 C++ 基本字符集中某些字符的系统。不用说,这样的系统极为罕见。

于 2009-08-05T17:18:10.887 回答
9

已提议在 C++0x 中删除三元图。也就是说,似乎仍然有强烈的论据支持它们 - 请参阅 C++ 委员会文件N2910,其中讨论了这一点。显然,EBCDIC 是需要它们的主要据点之一。

于 2009-08-05T17:39:34.637 回答
5

我见过在 90 年代初期使用三元组来帮助将 PL/1 程序从大型机转换为在 PC 上运行/编译/调试。

他们正在尝试使用 PL/I 到 C 编译器在 PC 上编辑 PL/I,并且他们希望代码在移回不支持花括号的大型机时能够正常工作。我建议他们可以使用宏,例如

#def BEGIN {    
#def END }  

或作为更友好的 PL/I 替代品

#def BEGIN ??<
#def END ??>

如果他们真的想变得花哨,他们可以尝试

#ifdef MAINFRAME
    #def BEGIN ??<
    #def END ??>
#else
    #def BEGIN {    
    #def END }  
#endif

然后程序看起来就像是用 Pascal 编写的。他们只是滑稽地看着我,一整天都不跟我说话。我不认为我责怪他们。:)

是什么扼杀了努力,而不是三图,而是平台之间的 IO 系统差异。在 PC 上打开文件与在大型机上打开文件有很大不同,它会引入太多的问题来保持相同的代码在两者上运行。

于 2009-08-05T17:32:35.960 回答
3

一些欧洲键盘没有(不是吗?)美国键盘所具有的所有标点符号,因为它们需要用于不寻常的字母字符的键。因此,例如(编造这个),瑞典语键盘在花括号所在的位置会有 A 形环。

为了适应这些用户,三元组是一种仅使用最常见的 ASCII 字符来输入标点符号的方法。

于 2009-08-05T17:20:29.743 回答
3

主要是因为 C 标准早在 1989 年就引入了它们,当时在某些机器上存在三字映射到的字符存在问题。到 1998 年发布 C++ 标准时,对三元组的需求并不大。他们在 C 上是个疣;它们在 C++ 上同样是一个疣。需要它们——尤其是在英语世界之外——这就是为什么它们被添加到 C.

于 2009-08-05T17:24:53.043 回答
2

他们在那里主要是出于历史原因。如今,大多数语言的大多数现代键盘都允许访问所有这些字符,但这曾经是一些欧洲键盘的问题。这就是发明三字的原因。

如果您不知道它们的用途,则不应使用它们。

不过,了解它们仍然是件好事,因为您可能会不小心在代码中使用它们。

于 2009-08-05T17:22:32.953 回答