Trigraph序列在C ++中的用途?


127

根据C ++'03 Standard 2.3 / 1:

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

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

在现实生活中,这意味着代码printf( "What??!\n" );将被打印,What|因为??!是由|字符替换的三部曲序列。

我的问题是使用三字组合的目的是什么?使用三字组合有任何实际的优势吗?

UPD:在回答中提到某些欧洲键盘没有所有的标点符号,因此非美国程序员在日常生活中必须使用三字母组合吗?

UPD2:默认情况下,Visual Studio 2010的Trigraph支持已关闭。


在欧洲键盘上,某些标点符号更难达到(以至于某些程序员使用美国布局来更快地键入)还没有看到完全缺少标点符号的地方-也许是斯拉夫语言?
peterchen

2
某些终端和/或虚拟化可能无法让您轻松访问某些字符,这可能会发生。以我的经验,主要罪犯是波浪号。
Francesco

1
在我的DE-deadkeys键盘上键入此字符,#是返回键,\是“ AltGr” +“ß”(在0旁边),^是“ ^” +“ ^”(由于死键;在1旁边) ,[是“ AltGr” +“ 8”,]是“ AltGr” +“ 9”,| 是“ AltGr” +“ <”,{是“ AltGr” +“ 7”,}是“ AltGr” +“ 0”,〜是“〜” +“〜”(因为死键位于#的正上方)。所以没什么大不了的。我的手指就像自己输入这些组合:-D
nonchip

1
我认为,拥有两个键盘布局并根据我在计算机上所做的工作来切换它们是正常的。这是中欧地区的常见方式。使用这些三部曲非常令人毛骨悚然。我投票赞成将其从标准中删除。
VX

Answers:


97

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

归结为以下事实:ISO 646字符集并没有C语法的所有字符,因此有些系统带有键盘和显示器,无法处理字符(尽管我认为这些字符很少见如今)。

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

'\?'

因此,有两种方法可以避免出现示例问题:

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

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

但是您必须记住在键入两个“?”时 您可能会开始制作三部曲的角色(当然,我从来没有想过)。

实际上,三合一和二合一是我每天都不担心的事情。但是您应该意识到它们的存在,因为每隔几年,您就会遇到一个与它们相关的错误(并且您将在一天的余下时间中诅咒它们的存在)。如果可以将编译器配置为在遇到有向图或有向图时发出警告(或出错),那就太好了,所以我可以知道我有一些我应该处理的东西。

而且,仅出于完整性考虑,有向图的危险性要小得多,因为它们会作为标记进行处理,因此字符串文字内的有向图不会被解释为有向图。

要获得有关C / C ++程序中标点符号的各种乐趣的不错的教育(包括一个Trigraph错误,它将最终使我脱发),请参阅Herb Sutter的GOTW#86文章


附录:

默认情况下,GCC似乎不会处理(也不会发出警告)三部曲。其他一些编译器具有关闭三字母组合支持的选项(例如IBM)。Microsoft开始在VS2008中支持警告(C4837),该警告必须显式启用(使用-Wall或其他方式)。


与C兼容是唯一原因吗?在现代C ++程序中能否满足它们?
09年

是的,C ++也支持三合一和二合一。
迈克尔·伯

4
我记得,至少我使用过的一个编译器(g ++?)在翻译trigraph和or digraph之前需要一个显式的命令行选项,否则会给出警告,但不能替代。
KTC

1
@ Jla3ep-我个人从来不需要三联字母,但是不幸的是编译器将使用它们来处理代码,因此您需要了解它们(以避免意外使用)。另外,如果您从其他地方获取代码,则可能会遇到它们的有意使用,但这将是非常不寻常的。我认为每20年以上我就会​​遇到一次有意使用的trigraph(这是IBM大型机的一些代码)。
迈克尔·伯尔

1
当三部曲的评论扩大到可以做令人惊奇的事情时,这真的让我不安。
约书亚

23

今天的孩子们!:-)

是的,国外设备,例如IBM 3270终端。如果我还记得,3270没有大括号!如果要在IBM mini /大型机上编写C,则必须为每个块边界使用可怜的三部曲。幸运的是,我只需要用 C编写软件来模拟某些IBM小型计算机设施,而不必在System / 36 实际编写C软件。

查看“ P”键旁边的内容:

键盘

嗯 很难说。在“回车”旁边还有一个额外的按钮,我可能会将它向后看:也许是缺少“ [” /“]”对。无论如何,如果您必须编写C,此键盘会使您感到悲伤。

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

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


1
键盘上有一个重置按钮。棒极了!奇怪的是首先引起了我的注意。
l46kok 2013年

10
任何想在EBCDIC机器上使用C ++ 17的人都应被判死刑。
SF。

除非一个平台没有的字符高于0646等,不能一切都可以用三合完成,通过要求每个实现定义或者一个反斜杠或其他任何字符,是不是在C字符集为完成“元”字符,将标准中所有对反斜杠的引用替换为“元”,并为ISO 646中未包含的C字符集的任何成员添加反斜杠/元转义符?
超级猫

22

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

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

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


7
“引进新设备可能是一个令人沮丧的缓慢过程”。特别是与标准化编程语言功能的快速而轻松的过程相比。
jforberg 2014年

4
如果这是`键盘布局的
笨拙之举

15

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


2
那是否意味着我将永远不会在现实生活中使用它们?
2009年

1
你生活在哪个国家?并非所有语言的所有键盘都具有必需的键。
David Thornley,2009年

2
是的,但是您可能需要意识到存在这种情况,以防在输入字符串文字时引起意外结果。
CB Bailey

4
@David Thornley:大多数现代系统支持C ++的所有基本字符,即使它们不在常规位置或需要使用修饰符序列进行键入。在系统字符集不能实际表示字符的系统上,仅需在源代码中维护三字母组合。我仍然认为这样的系统极为罕见。
CB Bailey

9

已提出将Trigraph用于C ++ 0x中的删除。也就是说,似乎仍然有很强的论据支持它们-请参阅讨论此问题的C ++委员会论文N2910。显然,EBCDIC是需要它们的主要据点之一。


是的,那“外语”!:-)
Roboprog

除了“来自客户反馈的内部调查的结果”之外,他们并没有说什么,但是很好。令我惊讶的是,尽管EBCDIC仍然被广泛使用(并且这些系统预期将使用C ++ 0x编译器)
peterchen 2010年

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上打开文件与大型机有很大的不同,它会引入太多的麻烦来使相同的代码在两者上运行。


PL / 1 = IBM的C版本(或多或少)。见我的评论:IBM终端没有'{'/'}'键:-(否则很难在其中之一上编写C [++]
。– Roboprog

3

主要是因为C标准是在1989年引入它们的,当时在某些机器上,三字组合映射到的字符存在问题。到1998年C ++标准发布时,对三联字母的需求并不大。他们是C的疣;它们与C ++一样。他们的需求-特别是在英语世界之外-这就是为什么将它们添加到C中的原因。


1
我一直怀疑IBM不会说英语:-)
Roboprog

3

一些欧洲键盘没有(不是吗?)具有美国键盘所具有的所有标点符号,因为它们需要按键来实现其不寻常的字母字符。因此,例如(弥补这一点),瑞典语键盘将在大括号处使用A形环。

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


4
Trigraph并不是真正关于数据输入的(它们使代码难以理解),它们更多地是关于实际上没有所需字符的系统。如果系统可以记录和显示字符-即使需要键入类似字母序列的三字母组合-不将三字母组合保留在源中也将容易得多。
CB Bailey

2

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

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

不过,最好还是注意它们,因为您可能会在代码中无意间无意地使用它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.