C 是什么?接线员呢?

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

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

它编译正确,似乎可以正常运行。似乎正在检查是否发生了错误,如果发生,则将其处理。但是我不太确定它的实际作用或作用方式。程序员似乎确实想表达对错误的感受。

我从未见过??!??!之前使用任何编程语言编写的文档,在任何地方都找不到它的文档。 (Google 无法帮助诸如??!??!搜索词??!??! )。它是做什么的,代码示例如何工作?

答案

??!是翻译成|三部曲 。所以说:

!ErrorHasOccured() || HandleError();

由于短路,其等效于:

if (ErrorHasOccured())
    HandleError();

本周最佳专家 (使用 C ++ 交易,但在这里相关),在这里我学到了。

三联字母的可能来源或 @DwB 在评论中指出,这更有可能是由于 EBCDIC 很难(再次)。 在 IBM developerWorks 板的讨论似乎支持这一理论。

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

三字符组序列使能输入未定义在不变代码集中的字符,如 ISO / IEC 646 所述,它是七位 US ASCII 代码集的子集。

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

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

该设备运行缓慢(10 cps),且嘈杂且丑陋,并且其 ASCII 字符集的视图以 0x5f 结尾,因此(在图片中仔细观察)没有任何按键:

{ | } ~

定义三元组以解决特定问题。想法是 C 程序可以使用 ASR-33 和其他缺少高 ASCII 值的环境中的 ASCII 子集。

您的示例实际上是两个??! ,每个意思| ,因此结果是||

然而,人们几乎可以肯定编写 C 代码有现代化的设备,1所以我的猜测是: 有人炫耀或会哄自理,留下一种复活节彩蛋的代码为你找到。

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

ASR-33电传打字机

ASR-33 电传打字机


1. 为此,三字母组合是由 ANSI 委员会发明的, C 取得巨大成功之后 ,他们第一次见面,因此,原始的 C 代码或编码人员都不会使用它们。

这是 C 三部曲??!| ,所以??!??!是运算符||

如前所述??!??!本质上是两个三元组 (再次变成??!??! ),它们被替换了 - 转换为|| ,即预处理器的逻辑 OR

下表包含每个三字组合应有助于消除其他三字组合的歧义:

Trigraph   Replaces

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

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

因此,看起来像??(??)的三元组最终将映射到[]??(??)??(??)将被[][]替换,依此类推,您就明白了。

由于在预处理过程中替换了trigr.c字母,因此您可以使用trigr.c程序使用cpp自己查看输出视图:

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

并使用以下命令进行处理:

cpp -trigraphs trigr.c

您将获得控制台输出

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

如您-trigraphs必须指定选项-trigraphs ,否则cpp会发出警告;这说明立体字是怎样的过去了,除了使可能碰到的人迷惑之外,没有现代价值


至于引入三字母组合的基本原理,在查看ISO / IEC 646 的历史记录部分时会更好地理解:

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

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

(强调我的)

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