2237

我看到一行 C 看起来像这样:

!ErrorHasOccured() ??!??! HandleError();

它编译正确,似乎运行正常。似乎它正在检查是否发生了错误,如果发生了,它会处理它。但我不确定它实际上在做什么或它是如何做的。看起来程序员确实在尝试表达他们对错误的感受。

我以前从未??!??!在任何编程语言中见过它,而且我在任何地方都找不到它的文档。(谷歌对搜索字词没有帮助??!??!)。它有什么作用以及代码示例如何工作?

4

4 回答 4

1777

??!是一个转换为 的三元组|。所以它说:

!ErrorHasOccured() || HandleError();

由于短路,这相当于:

if (ErrorHasOccured())
    HandleError();

本周大师(处理 C++,但在此处相关),我在哪里选择了这个。

三元组的可能起源或@DwB 在评论中指出,这更有可能是由于 EBCDIC 很困难(再次)。IBM developerworks 板上的讨论似乎支持该理论

来自 ISO/IEC 9899:1999 §5.2.1.1,脚注 12(h/t @Random832):

trigraph 序列支持输入未在 ISO/IEC 646 中描述的不变代码集中定义的字符,它是七位美国 ASCII 代码集的子集。

于 2011-10-19T16:58:44.797 回答
518

好吧,为什么这通常存在可能与您的示例中存在的原因不同。

这一切都始于半个世纪前,将硬拷贝通信终端重新用作计算机用户界面。在最初的 Unix 和 C 时代,那是 ASR-33 Teletype。

这个设备很慢(10 cps),嘈杂和丑陋,它对 ASCII 字符集的视图以 0x5f 结尾,所以它(仔细看图片)没有任何键:

{ | } ~ 

定义三元组以解决特定问题。这个想法是 C 程序可以使用在 ASR-33 上找到的 ASCII 子集,并且在其他环境中缺少高 ASCII 值。

您的示例实际上是两个??!,每个含义|,所以结果是||

但是,几乎按照定义编写 C 代码的人都拥有现代化的设备,1所以我的猜测是:有人在炫耀或自娱自乐,在代码中留下一种复活节彩蛋让你找到。

它确实有效,它导致了一个广受欢迎的 SO 问题。

ASR-33 电传打字机

                                            ASR-33 电传打字机


1. 就此而言,三元组是由 ANSI 委员会发明的,该委员会在C 取得巨大成功后首次会面,因此原始 C 代码或编码人员都不会使用它们。

于 2011-10-19T21:09:06.257 回答
188

这是一个 C三元组??!|??!??!运算符也是||

于 2011-10-19T16:58:56.063 回答
176

如前所述??!??!,本质上是将两个三元组??!??!再次)混合在一起,由预处理器替换翻译为||,即逻辑 OR 。

下表包含每个三元组应该有助于消除替代三元组组合的歧义:

Trigraph   Replaces

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

资料来源:C:参考手册第 5 版

所以一个看起来像的三元组??(??)最终将映射到[]??(??)??(??)将被替换[][]等等,你明白了。

由于在预处理过程中替换了三元组,因此您可以使用一个愚蠢的程序cpp来自己查看输出:trigr.c

void main(){ const char *s = "??!??!"; } 

并使用以下方法处理它:

cpp -trigraphs trigr.c 

你会得到一个控制台输出

void main(){ const char *s = "||"; }

如您所见,-trigraphs必须指定该选项,否则cpp将发出警告;这表明三合字母已成为过去,除了使可能碰到它们的人感到困惑之外,没有现代价值


至于引入三元组背后的基本原理,在查看ISO/IEC 646 的历史部分时可以更好地理解:

ISO/IEC 646 及其前身 ASCII (ANSI X3.4) 在很大程度上认可了电信行业中有关字符编码的现有做法。

由于 ASCII 没有提供除英语以外的语言所需的许多字符,因此制作了许多国家变体,用所需的字符替换了一些较少使用的字符

(强调我的)

因此,从本质上讲,某些国家变体中替换了一些需要的字符(存在三合符的字符)。这导致使用由其他变体仍然具有的字符组成的三元组的替代表示。

于 2016-03-25T02:24:53.770 回答