我看到了一行C,看起来像这样:
!ErrorHasOccured() ??!??! HandleError();
它正确编译,看起来运行正常。似乎正在检查是否发生了错误,如果发生,则将其处理。但是我不太确定它的实际作用或作用方式。看起来程序员似乎正在尝试表达他们对错误的感觉。
我以前从未以任何编程语言见过??!??!
,而且在任何地方都找不到它的文档。 (Google无法帮助搜索??!??!
之类的字词。)它是做什么的,代码示例如何工作?
??!
是转换为trigraph的|
。它说:
!ErrorHasOccured() || HandleError();
由于短路,它等效于:
if (ErrorHasOccured())
HandleError();
[Guru of the Week(与C ++交易,但在这里相关),在这里我选择了。
Possible origin of trigraphs或@DwB在评论中指出,更有可能是由于EBCDIC很难(再次)。 This在IBM developerWorks董事会上的讨论似乎支持该理论。
从ISO / IEC 9899:1999§5.2.1.1,脚注12(h / t @ Random832):
三字母序列允许输入在不变代码集中未定义为在ISO / IEC 646中进行了描述,它是七位美国ASCII代码集的子集。
嗯,为什么它通常存在与为什么它在您的示例中存在。
这一切始于半个世纪前,将硬拷贝通信终端重新用作计算机用户界面。在最初的Unix和C时代是ASR-33电传打字机。
此设备速度很慢(10 cps),且嘈杂且丑陋,其ASCII字符集的视图以0x5f结尾,因此(在图片中仔细观察)没有任何键:
{ | } ~
The trigraphs被定义为解决特定问题。想法是C程序可以使用ASR-33和其他缺少高ASCII值的环境中的ASCII子集。
您的示例实际上是
??!
的两个,每个都表示|
,所以结果是||
。
但是,几乎按照定义编写C代码的人具有现代化的设备,1所以我的猜测是:有人炫耀或自娱自乐,在代码中留出一种复活节彩蛋供您查找。
确实有效,它导致了一个非常受欢迎的SO问题。
ASR-33电传打字机
这是C trigraph。 ??!
是|
,所以??!??!
是运算符||
如前所述,??!??!
本质上是两个trigraphs(再次是??!
和??!
),它们被预处理器替换并转换为||
,即logical OR。
下表包含每个三字组合应有助于消除其他三字组合的歧义:
Trigraph Replaces
??( [
??) ]
??< {
??> }
??/ \
??' ^
??= #
??! |
??- ~
来源:C: A Reference Manual 5th Edition] >>
因此,看起来像??(??)
的三元组最终将映射到[]
,??(??)??(??)
将被[][]
代替,依此类推,您就明白了。
由于在预处理过程中替换了三边形,您可以使用愚蠢的cpp
程序使用cpp
自己查看输出视图:
trigr.c
并使用:]进行处理>
void main(){ const char *s = "??!??!"; }
您将获得控制台输出
cpp -trigraphs trigr.c
您会注意到,必须指定选项
。void main(){ const char *s = "||"; }
,否则-trigraphs
会发出警告;这表明三角图已成为过去,除了混淆可能会碰到它们的人之外,没有任何现代价值
关于引入三元组的基本原理,在查看cpp
时会更好地理解:
ISO / IEC 646及其先前的ASCII(ANSI X3.4)在电信行业中广泛认可了有关字符编码的现有做法。
由于ASCII没有提供英语以外的语言所需的许多字符,所以产生了许多国家变体,用需要的字符代替了一些较少使用的字符
。(我的重点)
因此,从本质上讲,某些国家变体中替换了一些需要的字符(存在三字母组合的字符)。这导致使用由其他变体仍具有的字符组成的三字组合表示的替代表示形式。