今天是否还在使用双字符和三字符?

42

考虑到以前在C和C++中使用双字母组合和三字母组合的原因,现在是否有人将它们放入正在编写的代码中?是否还有大量需要维护的遗留代码包含它们?

(注意:这里,“digraph”不是指“有向图”。Digraphtrigraph都有多重含义,但此处意图使用的是像??=<:这样的序列,以代替像#[这样的字符。)


1
我从来没有刻意去看过它们,但是我从事游戏开发,遗留代码要少得多得多。 - Michael Dorgan
4
来试试谷歌代码搜索吧!比如:http://www.google.com/codesearch#search/&q=%5C?%5C?%5C(%20lang:%5Ec$&type=cs 可以查找所有 ??( 的实例。请享受这个过程! - Ray Toal
不要忘记使用引号!@Ray - 谢谢。我现在将花一个小时查找脏话并嘲笑伴随其中的烂代码。 - Anne Quinn
3
@Ray - 谢谢,很有趣!显然,绝大多数出现在字符串和注释中,其中 ??(x) 是一个函数调用的伪代码。通过查找 ??< 来缩小搜索范围,这代表 { 符号,在任何 C 源代码中都是必不可少的。在所有 14 页的搜索结果中,没有一个真正的三字符组例子。它们主要是 HTML 的伪代码,还有一些编译器/编译器测试和 base64 编码的文本。 (我感兴趣是因为我正在编写一个 C++11 预处理器来实践。) - Potatoswatter
2
@Matthieu:但是如果您使用这样的选项,您的代码将依赖于它,而且如果没有该选项编译,则要么无法编译,要么具有不同的含义。我宁愿收到警告,以便完全避免三字符序列。 - Keith Thompson
显示剩余2条评论
5个回答

26
我不确定,但你最有可能在IBM大型机环境中找到使用digraphs和trigraphs。EBCDIC字符集不包括C语言所需的某些字符。
另一个使用digraphs和trigraphs的理由是,这些7位ASCII字符集用重音字母替换了一些标点符号字符,但这个理由可能今天已经不那么相关了。
在这样的环境之外,我认为trigraphs更常被错误地使用而不是故意使用,例如:
puts("What happened??!");

参考资料:三字符序列(trigraphs)是在1989年的ANSI C标准中引入的(本质上成为了1990年ISO C标准)。它们包括:

??= #     ??) ]     ??! |
??( [     ??' ^     ??> }
??/ \     ??< {     ??- ~

替换可以发生在源代码的任何地方,包括注释和字符串字面量。
双字符是某些记号的替代拼写方式,不影响注释或字面量。
<: [      :>   ]
<% {      %>   }
%: #      %:%: ##

二元组是由1995年对1990年ISO C标准的修订引入的。


那些7位ASCII-ish字符集在1972年被标准化为ISO-646,到1980年代它们已经开始不再使用,被8位ISO-8859变体(包括Windows-1252)所取代,到了1990年代。后者包括所有7位ASCII字符,不需要在C代码中使用三字符。如果还有遗留的ISO-646系统存在,它们早已过时,没有人会为它们编写新的C代码。 - han
2
在这种情况下,写入 puts("What happened?" "?!\n"); 以获得正确的输出。 - Gzorg
2
@Gzorg 三字符序列也可以通过转义第二个“?”来规避,例如:puts("What happened?\?!\n"); - Rhubbarb
1
实际上,三字母符号(在EBCDIC之后)的次要原因之一是,1970年代和1980年代的许多微型计算机配备了与今天PC / Apple键盘标准化非常不同的终端键盘。每个供应商都有自己的键盘布局,有时甚至在不同的行中存在变化。在某些终端上,输入某些符号并不容易或直接不可能,例如波浪符“~”甚至“(商业) at”符号“@”,因此需要使用三字母符号。我认为C甚至没有在非IBM系统上实现ASCII。 - mctylr
1
@mctylr 许多70年代末和90年代初的微型计算机也没有遵循IBM Selectric或PC标准,并且没有所有必需的字符来避免使用_n_-graphs。例如,Atari在其8位机器上使用的ASCII变体ATASCII不包括花括号或竖线。为了增加乐趣,我在那台机器上使用了一个使用非标准bigraphs的C编译器——(**)用于打开和关闭花括号。 - dodgethesteamroller

17

有一个C++1z的提案(在C++1y之后的下一个标准,希望能够成为C++14)旨在从标准中删除三字符序列。他们对一份未公开的大型代码库进行了案例研究:

案例研究

我们检查了一个大型代码库中类似三字符序列的结构使用情况。我们发现:

923个实例在字符串文字中转义?以避免三字符替换:string pattern() const { return "foo-????\?-of-?????"; }

4个实例在测试代码中故意使用三字符序列:两个在编译器的测试套件中,另外两个在boost的预处理器库的测试套件中。

0个实例在生产代码中故意使用三字符序列。三字符序列继续给C++用户带来负担。

该提案指出(原始提案中加粗强调):

如果从语言中完全删除三字符序列,则希望支持它们的实现仍可以这样做:其从物理源文件字符到基本源字符集的实现定义映射可以包括三字符序列转换(甚至可以在原始字符串字面值中避免这样做)。 为了向后兼容,我们不需要在标准中使用三字符序列。

4
所有逃逸的三字符序列会发生什么?! - Praxeolitic
1
@Praxeolitic 我看明白了你在干什么。知道吗,四年后你的玩笑还是很受欢迎的。至于实际问题,\? 仍然表示字面上的 ? 字符,因为它是定义的转义序列之一,无论三字符序列是否存在。 - mtraceur
我同意一些看起来奇怪的三重/双重字符应该被删除,但是有一些有用的三重/双重字符,比如andornotbitandnot_eq,它们看起来非常明确,因此可以强制执行代码意图。 - daparic

9

1
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。 - ChrisH
@ChrisH:在我看来,这个链接并不是答案(也就是说,这不是一个仅包含链接的答案)。该链接只是为了方便而添加的。 - undur_gongor
3
说得对。但我想考虑到这是一个回答已经被接受并获得17个赞的将近3年前的问题,这已经是相当学术性的了。 - ChrisH

5
三元组和双元组的使用已经过时,仅存在于非常旧的代码中,这些代码是在非常有限的环境下创建的。如果您尝试在像VS这样的现代编译器上编译包含三元组的代码,它通常无法编译,除非您指定链接器选项。对于Visual Studio,该选项是"/Zc:trigraphs"。
为什么它们存在呢?因为C ++委员会从未发布过可能“破坏”传统代码的更改,因为好与坏是相对的。有个轶事说他们曾提出并支持删除它们,但被一位孤独的IBM代表拦住了。

EBCDIC仍然在旧的IBM大型机上使用,但不包括编写C/C++所需的所有字符 :( - Matthieu M.
2
为什么它会成为一个 链接器 选项?三字母符号由编译器处理;链接器甚至不需要意识到它们。 - Keith Thompson

3
我知道这个问题很老了,但现在有一个合法的用途:没有实际键盘的触摸屏。例如,如果您通过平板电脑进行编码,典型的美国键盘布局可能无法以完整形式提供,尽管这种情况希望很少见到,因为它可能非常繁琐(对于我的分配运算符需要三次点击)。如果可能的话,我个人不使用它们,但在缺乏它们所代表的实际令牌的情况下,它们是有用的。

再次强调,我真的希望人们在可能的情况下避免使用它们,但这是了解和使用它们的一个原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接