c - overload - 重载运算符




什么是C ??!??! 运营商呢? (3)

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

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

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

我从来没有见过??!??! 之前使用任何编程语言,我无法在任何地方找到文档。 (Google对搜索字词没有帮助,例如??!??! )。 它做什么以及代码示例如何工作?


??! 是翻译为|trigraph 。 所以它说:

!ErrorHasOccured() || HandleError();

由于短路,这相当于:

if (ErrorHasOccured())
    HandleError();

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

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

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

trigraph序列允许输入未在不变代码集中定义的字符,如ISO / IEC 646中所述,它是7位US ASCII代码集的子集。


如前所述??!??! 基本上是两个trigraphs (再次合并),它们一起变得被替换 - 翻译成|| ,即预处理器的逻辑或

包含所有三字母组合的以下图像应该有助于消除其他三字母组合的歧义:

(从C:A参考手册第5版获取的图像

因此,看起来像??(??)的三角形最终将映射到[]??(??)??(??)将被[][]等替换,您就会明白。

由于trigraph在预处理过程中被替换,您可以使用trigr.c程序使用cpp自己获取输出视图:

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

并用以下方式处理它:

cpp -trigraphs trigr.c 

你会得到一个控制台输出

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

你可以注意到,必须指定选项-trigraphs ,否则cpp将发出警告; 这表明三撇子如何成为过去的事物,除了混淆可能碰到它们的人之外没有现代价值

关于引入trigraphs的基本原理,在查看ISO/IEC 646History部分时更好理解:

ISO / IEC 646及其前身ASCII(ANSI X3.4)在很大程度上支持电信行业字符编码方面的现有做法。

由于ASCII没有提供除英语以外的其他语言所需的许多字符,因此制作了许多国家变体,用一些不常用的字符替换为需要的字符

(强调我的)

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


那么,为什么这存在一般可能不同于它为什么存在于你的例子。

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

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

{ | } ~ 

trigraphs被定义为解决一个特定的问题。 这个想法是C程序可以使用ASR-33上找到的ASCII子集以及其他缺少高ASCII值的环境。

你的例子其实是两个??! ,每个含义| ,所以结果是||

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

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

ASR-33电传打字机

1.对于这个问题,trigraphs是由ANSI委员会发明的,它 C成为失控的成功之后首次遇到,所以原始的C代码或编码器都不会使用它们。





trigraphs