什么是C ??!??!操作员呢?

Peter Olson 1710 c operators trigraphs

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

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

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

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

user786653.. 1390

??!是一个翻译为的三字母|.所以它说:

!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中描述的不变代码集中定义的字符,ISO/IEC 646是七位US ASCII代码集的子集.

  • 如果您的键盘没有例如"|",则最初需要Trigraphs 符号.这是程序员故意烦人或者一些奇怪的编辑'功能' (320认同)
  • 一个完全可读的替代方案是`ErrorHasOccurred()&& HandleError();`也就是说,如果你习惯于shell脚本.:) (46认同)
  • 是的,它相当于`if(ErrorHasOccured())HandleError()`.值得庆幸的是,你通常只在perl代码中遇到这个习惯用法. (25认同)
  • 读它为"没有ErrorHasOcurred或你必须HandleError",@ SparkyRobinson. (16认同)
  • 它不一定是EBCDIC - 需要三字符的字符集几乎完全匹配ISO-646中不是不变的字符集(即旧的"国家ascii"标准). (14认同)
  • 布尔运算符严格评估LTR,IIRC. (6认同)
  • @ Random832:该标准有一个脚注说:_三字符序列允许输入未在ISO/IEC 646中描述的不变代码集中定义的字符,ISO/IEC 646是7位US ASCII代码集的子集. (3认同)
  • @PeterOlson - 对.如果`!ErrorHasOccured()`解析为`true`则它会短路,否则会调用`HandleError()`. (2认同)

DigitalRoss.. 379

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

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

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

{ | } ~ 

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

你的例子实际上是两个??!,每个意思|,所以结果是||.

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

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

ASR-33电传打字机

                                            ASR-33电传打字机


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

  • 参见[这些](http://en.wikipedia.org/wiki/ASCII#Incompatibility_vs_interoperability)[two](http://en.wikipedia.org/wiki/ISO/IEC_646)维基百科的文章.我已经足够大了,仍然记得7位国家字符集的时代(虽然我确信它们仍然留在一些黑暗的未经扫描的角落里),而我第一次从中学到C的书发现有必要警告它'if(x || y){a [i] ='\ 0'的可能性; 看起来像`if(xööy)äaÄiÅ='Ö0'; å`在错误的字符集中. (27认同)
  • 这不是键盘和字符集中唯一缺少字符的情况.对于三十多岁及以上的很多人来说,Commodore 64可能更为熟悉 - 显示的字符集都缺少括号(也可能是条形和波形) - 在这种情况下,因为"ASCII"不是ASCII .在ECMA-6(几乎总是称为ASCII,但不是US-ASCII)中,有18个特定于区域的代码,但我不知道它们是哪些代码.我可以肯定的一件事 - 在英国的"ASCII"中,`#`被```替换掉了.在其他地区,也许"ASCII"没有括号等. (12认同)
  • 有趣的故事我得告诉你...... IBM RS/6000工作站的XL Fortran编译器是从XL C编译器开发的.在前几个版本中,他们意外地离开了三字母处理,因此有一些合法的Fortran字符序列(在字符串中,IIRC)被误解为C三字符,导致一些有趣的错误! (11认同)
  • 另一个有趣的历史记录是,Unix(这是C平台上的大型平台)可能是第一个将默认字母值默认为小写而不是大写的系统(可能是第一个整体).虽然我没有亲眼看到许多现代系统,但我认为这是一个复杂的真实迹象.除了真正唯一体面的操作系统外,Unix还将你的大写转换为低级,而不是相反.那些家伙真的很酷. (7认同)
  • Atari 8位计算机的类似ATASCII字符集也缺少{}以及〜和`. (4认同)

Joel Falcou.. 147

这是一个C 三连词.??!|,??!??!运营商也是如此||

  • 为什么有人会用?? 而不是| ??? / (5认同)
  • trigraph来自某个键盘没有现在拥有的所有键的时期.当一些文本编辑器为特殊事物保留特殊字符时,它也会有效.它主要是过去的遗物和一个quizz启动器;) (3认同)

Jim Fasaraki.. 101

如前所述??!??!实际上是两个三合(??!??!捣成泥再一起),其被替换翻译到||,即逻辑或,由预处理器.

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

在此输入图像描述 (图片取自C:A参考手册第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没有提供除英语之外的语言所需的许多字符,因此制作了许多国家变体,用一些较少使用的字符替换了所需的字符.

(强调我的)

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

  • ⁺¹用于其他三角形表. (4认同)