提问



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


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


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


我以前从未在任何编程语言中看过??!??!,而且我无法在任何地方找到它的文档。(Google对??!??!等搜索术语没有帮助)。它做了什么以及代码示例如何工作?

最佳参考


??!是一个翻译为|的三字母。所以它说:[32]


!ErrorHasOccured() || HandleError();


由于短路,相当于:


if (ErrorHasOccured())
    HandleError();


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


三角形的可能起源或@DwB在评论中指出它更可能是由于EBCDIC很难(再次)。这个关于IBM developerworks董事会的讨论似乎支持这一理论。[34] [35]


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



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


其它参考1


那么,为什么这一般存在可能与你的例子中存在的原因不同。


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


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


{ | } ~ 


定义三字母以解决特定问题。我们的想法是,C程序可以使用ASR-33上的ASCII子集以及缺少高ASCII值的其他环境。[36]



??你的例子实际上是??!中的两个,每个都意味着|,所以结果是||



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


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


[37]


                       &NBSP ;???????????????????? ASR-33 Teletype


1。就此而言,三角形是由ANSI委员会发明的,该委员会在 C成功失败后首次遇到,因此原始的C代码或编码器都不会使用它们。

其它参考2


它是一个C三字符。??!|,所以??!??!是运算符|| [38]

其它参考3


正如已经陈述的那样??!??!本质上是两个三字母(??!??!再次合并而被替换 - 被翻译为||,即<强预>逻辑OR ,由预处理器完成。 [39] [40]


包含所有三字母的下图将有助于消除替代三字母组合的歧义:



(图片取自 C:A参考手册第5版) [41] [42]


所以看起来像??(??)的三元组最终将映射到[]??(??)??(??)将被[][]取代,依此类推,你得到了这个想法。


由于在预处理过程中替换了三字符,你可以使用cpp自己查看输出,使用愚蠢的trigr.c程序:[43]


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


并处理它:


cpp -trigraphs trigr.c 


你将得到一个控制台输出


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


您可以注意到,必须指定选项-trigraphs,否则cpp将发出警告;这表明三字母是如何成为过去的事物,除了让可能碰到它们的人感到困惑之外没有现代价值。





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



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

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



(强调我的)


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