??!??!有什么作用运算符在 C 中做什么?

What does the ??!??! operator do in C?

提问人:Peter Olson 提问时间:10/20/2011 最后编辑:Peter Olson 更新时间:8/19/2021 访问量:391576

问:

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

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

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

我以前从未在任何编程语言中看到过它,我在任何地方都找不到它的文档。(谷歌对这样的搜索词没有帮助)。它有什么作用,代码示例是如何工作的???!??!??!??!

C 运算符 三字

评论

87赞 johnthagen 7/15/2018
可悲的是,这个程序的瑰宝在 C++17 及更高版本中不起作用
14赞 Keith Thompson 10/6/2022
三字将在 ISO C23 标准中删除。
0赞 Peter Mortensen 11/7/2022
这是 Kanetkar 的谜题之一吗?

答:

2031赞 user786653 10/20/2011 #1

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

!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 中描述,它是 7 位美国 ASCII 代码集的子集。

评论

549赞 Martin Beckett 10/20/2011
最初需要三字,以防您的键盘没有例如“|”符号。这里要么是程序员故意烦人,要么是一些奇怪的编辑器“功能”
37赞 Random832 10/20/2011
它不一定是 EBCDIC——需要三元组的字符集几乎与 ISO-646(即旧的“国家 ascii”标准)中不变的字符集完全匹配。
95赞 Yam Marcovic 10/24/2011
一个完全可读的替代方案是:也就是说,如果您习惯于 shell 脚本。:)ErrorHasOccurred() && HandleError();
13赞 Luciano 4/15/2015
请注意,许多编码标准明确禁止使用 Trigraph 和 Digraphs,许多编译器和静态分析器都会标记它们的使用。
13赞 val - disappointed in SE 12/16/2018
自 C++17 起无效 :|
203赞 Joel Falcou 10/20/2011 #2

这是一个 C 三元组。 是,运算符也是如此??!|??!??!||

评论

14赞 Joel Falcou 3/24/2017
Trigraph 来自一个时期,当时一些键盘没有现在拥有的所有键。当一些文本编辑器为特殊事物保留特殊字符时,它也会出现。它主要是过去的遗物和测验的推动者;)
9赞 Owl 1/12/2019
因为有些键盘显然没有“|”,所以有些人别无选择,只能反复用头撞键盘,直到出现三字形图,为他们提供所需的符号。
4赞 David R Tribble 10/26/2019
然后是头文件。<iso646.h>
590赞 DigitalRoss 10/20/2011 #3

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

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

这个设备很慢(10 cps),嘈杂和丑陋,它对ASCII字符集的视图在0x5f结束,所以它(仔细看图片)没有键:

{ | } ~ 

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

您的示例实际上是??!中的两个,每个都表示 |,因此结果是 ||

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

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

ASR-33 Teletype

ASR-33 电传打字机


1. 就此而言,三元组是由 ANSI 委员会发明的,该委员会在 C 取得巨大成功首次开会,因此没有一个原始的 C 代码或编码人员会使用它们。

评论

35赞 10/20/2011
这并不是键盘和字符集中缺少字符的唯一情况。Commodore 64 对于许多 30 多岁及以上的人来说可能更熟悉 - 显示的字符集都缺少大括号(可能还有条形和波浪号) - 在这种情况下,因为“ASCII”不是 ASCII。在 ECMA-6(几乎总是称为 ASCII,但不是 US-ASCII)中,有 18 个特定于区域的代码,但我不知道它们是哪些代码。我可以肯定地说的一件事是 - 在英国的“ASCII”中,被替换为.在其他地区,也许“ASCII”没有大括号等。#£
9赞 dan04 10/20/2011
Atari 8位计算机的类似ATASCII字符集也缺少{}以及~和'。
55赞 Ilmari Karonen 10/20/2011
请参阅这两维基百科文章。我差不多大了,还记得 7 位国家字符集的时代(尽管我敢肯定它们仍然在一些黑暗的未被扫过的角落里徘徊),而我第一次学习 C 的书发现有必要警告一下在错误的字符集中看起来像的可能性。if (x || y) { a[i] = '\0'; }if (x öö y) ä aÄiÅ = 'Ö0'; å
17赞 DigitalRoss 10/26/2011
另一个有趣的历史说明是,Unix(这是C语言所采用的大平台)可能是第一个将字母值默认为小写而不是大写的系统(也许是第一个)。虽然我没有亲眼看到很多当代系统,但我认为这是成熟的真正标志。除了是唯一像样的操作系统之外,Unix 还将大写字母转换为小写字母,反之亦然。那些家伙真的很酷。
29赞 Phil Perry 4/12/2014
有趣的故事,我得告诉你......IBM RS/6000 工作站的 XL Fortran 编译器是从 XL C 编译器开发的。在最初的几个版本中,它们不小心留在了三元组处理中,因此有一些合法的 Fortran 字符序列(在字面字符串中,IIRC)被误解为 C 三元组,导致了一些有趣的错误!
201赞 Dimitris Fasarakis Hilliard 3/25/2016 #4

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

下表包含每个三元组,应有助于消除备用三元组组合的歧义:

Trigraph   Replaces

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

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

因此,一个看起来像的三元组最终会映射到 ,将被替换为 等等,你就明白了。??(??)[]??(??)??(??)[][]

由于三元组在预处理过程中被替换,因此您可以使用cpp自己获取输出视图,使用一个愚蠢的程序:trigr.c

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

并使用以下方法进行处理:

cpp -trigraphs trigr.c 

你将获得

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

如您所见,必须指定该选项,否则将发出警告;这表明三叉戟已成为过去,除了让可能碰到它们的人感到困惑之外,没有任何现代价值-trigraphscpp


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

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

由于 ASCII 没有提供英语以外的其他语言所需的字符数量,因此制作了一些国家变体,用需要的字符替换一些较少使用的字符

(强调我的)

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

评论

4赞 Andrew 9/23/2021
很好的解释......这也说明了为什么占位符(如 may not generate what you expected) (这实际上会产生char *date = "??-??-??!"char *date = "~~|";)
1赞 wojtow 3/8/2022
似乎大多数典型的 C 代码如果完全使用三元组实现将很难阅读:if(data??(x??)??(y??)=='??/r' ??!??! data??(x??)??(y??)==0) ??< break; ??>
2赞 quetzalcoatl 4/8/2022
@wojtow不,你只是没有进行足够的硬编码:)只需添加一些即可增加可读性?: