根据C ++'03标准2.3 / 1:
在进行任何其他处理之前,每次出现以下三个字符序列之一(“三字符序列”)将被表1中所示的单个字符替换。
---------------------------------------------------------------------------- | trigraph | replacement | trigraph | replacement | trigraph | replacement | ---------------------------------------------------------------------------- | ??= | # | ??( | [ | ??< | { | | ??/ | \ | ??) | ] | ??> | } | | ??’ | ˆ | ??! | | | ??- | ˜ | ----------------------------------------------------------------------------
在现实生活中,这意味着代码printf( "What??!\n" );
将导致打印What|
,因为??!
是一个被|
字符替换的三字符序列。
我的问题是使用三字母的目的是什么?使用三字母有什么实际优势吗?
UPD :在答案中提到一些欧洲键盘没有所有标点字符,所以非美国程序员必须在日常生活中使用三字母?
UPD2 :默认情况下,Visual Studio 2010默认启用了三字母支持。
答案 0 :(得分:89)
This question (about the closely related digraphs)有答案。
归结为ISO 646字符集没有C语法的所有字符这一事实,因此有些系统的键盘和显示器无法处理字符(尽管我想这些现在很少见。)
一般情况下,您不需要使用它们,但您需要了解它们,以确定您遇到的问题。 Trigraphs是“?
”字符具有转义序列的原因:
'\?'
因此,有两种方法可以避免您的示例问题:
printf( "What?\?!\n" );
printf( "What?" "?!\n" );
但你必须记住当你输入两个'?'时你可能会开始三角形的角色(这肯定不是我正在考虑的事情)。
在实践中,三元组和有向图是我日常不用担心的事情。但是你应该知道它们,因为每隔几年你就会遇到一个与它们相关的错误(你会花一天的时间来诅咒它们的存在)。如果编译器可以被配置为在遇到三字符或有向图时发出警告(或错误),那将是很好的,所以我知道我有一些我应该知道处理的事情。
而且为了完整性,有向图的危险性要小得多,因为它们被作为标记处理,因此字符串文字中的有向图不会被解释为有向图。
要想在C / C ++程序中使用标点符号进行各种有趣的教育(包括一个可以让我把头发拉出来的三字母错误),请查看Herb Sutter's GOTW #86 article。
附录:
默认情况下,GCC似乎不会处理(并将警告)三字符。其他一些编译器可以选择关闭三元组支持(例如IBM)。 Microsoft开始在VS2008中支持警告(C4837),必须明确启用(使用-Wall或其他)。
答案 1 :(得分:20)
来自The C++ Programming Language
特别版,第829页
ASCII特殊字符
[
,]
,{
,}
,|
和\
占用指定为字母的字符集位置通过ISO。在大多数欧洲国家ISO-646字符集中,这些位置由英语字母表中没有的字母占据。提供了一组三字母组合,以允许使用真正标准的最小字符集以便携方式表达国家字符。这对于程序的交换很有用,但它不会让人们更容易阅读程序。当然,这个问题的长期解决方案是让C ++程序员获得支持其母语和C ++的设备。不幸的是,这似乎对某些人来说是不可行的,而新设备的引入可能是一个令人沮丧的缓慢过程。
答案 2 :(得分:18)
今天的孩子们! : - )
是的,外国设备,如IBM 3270终端。如果我记得的话,3270没有花括号!如果您想在IBM mini / mainframe上编写C,那么必须为每个块边界使用可怜的三字符。幸运的是,我只需要在C中编写软件来模拟一些IBM小型机设备,而不是实际在 System / 36上编写C软件。
查看“P”键旁边: http://www.9999hp.net/keyboard/temp/1389260-big.jpg
嗯。很难说。 “回车”旁边有一个额外的按钮,我可能会倒退:可能是“[”/“]”对丢失了。无论如何,如果你不得不写C,这个键盘会让你感到悲伤。
此外,这些终端显示EBCDIC,IBM的“本机”主机字符集,而不是ASCII(感谢Pavel Minaev提醒)。
另一方面,就像GNU C指南所说:“你不需要这种脑损伤。” gcc编译器默认禁用此“功能”。
答案 3 :(得分:13)
它们适用于缺少C ++基本字符集中某些字符的系统。毋庸置疑,这种系统非常罕见。
答案 4 :(得分:8)
已经建议在C ++ 0x中删除Trigraph。也就是说,支持它们似乎仍有很强的论据 - 参见C ++委员会文件N2910,讨论了这一点。显然,EBCDIC是需要它们的一个主要据点。
答案 5 :(得分:4)
我见过在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上打开文件与大型机有很大的不同,它会引入太多的kludges来保持相同的代码在两者上运行。
答案 6 :(得分:3)
某些欧洲键盘没有(没有?)具有美国键盘所具有的所有标点字符,因为它们需要键盘来显示其不寻常的字母字符。所以例如(这样做),瑞典键盘将有一个大括号的A形环。
为了适应这些用户,三字母是一种仅使用最常见的ASCII字符输入标点符号的方法。
答案 7 :(得分:2)
他们主要是出于历史原因。如今,大多数语言的大多数现代键盘都允许访问所有这些字符,但这曾经是一些欧洲键盘的问题。这就是为什么发明了三角形的原因。
如果您不知道它们的用途,则不应使用它们。
但是,知道它们仍然很好,因为你可能会在你的代码中意外地和无意地使用它们。答案 8 :(得分:2)
主要是因为C标准在1989年引入了它们,当时在某些机器上存在三字符映射到的字符存在问题。当C ++标准于1998年发布时,对三字母的需求并不大。他们是C的疣;它们与C ++一样多。他们需要 - 特别是在英语世界之外 - 这就是为什么他们被添加到C。