我看到了一行看起来像这样的C代码:
!ErrorHasOccured() ??!??! HandleError();
这段代码编译正确且似乎正常运行。它似乎在检查是否发生了错误,如果发生了错误,则进行处理。但是我不确定它实际上在做什么或者是如何完成的。看起来程序员试图表达他们对错误的感受。
我从未在任何编程语言中见过??!??!
,也找不到它的文档(谷歌搜索像??!??!
这样的搜索术语无法帮助)。它是用来做什么的,以及这个代码示例是如何工作的?
我看到了一行看起来像这样的C代码:
!ErrorHasOccured() ??!??! HandleError();
这段代码编译正确且似乎正常运行。它似乎在检查是否发生了错误,如果发生了错误,则进行处理。但是我不确定它实际上在做什么或者是如何完成的。看起来程序员试图表达他们对错误的感受。
我从未在任何编程语言中见过??!??!
,也找不到它的文档(谷歌搜索像??!??!
这样的搜索术语无法帮助)。它是用来做什么的,以及这个代码示例是如何工作的?
??!
是一个将被翻译为 |
的三字符组合。因此,它的含义是:
!ErrorHasOccured() || HandleError();
由于短路,这等价于:
if (ErrorHasOccured())
HandleError();
Guru of the Week (处理 C++ 相关的问题,但在此处也相关),我从那里获得了这个信息。
三字符序列的可能来源 或如 @DwB 在评论中指出,更可能是由于 EBCDIC 而变得困难 (再一次)。 这篇 IBM developerworks 论坛上的讨论似乎支持了这个理论。
来自 ISO/IEC 9899:1999 §5.2.1.1,注脚12 (感谢@Random832):
三字符序列使得可以输入在 ISO/IEC 646 描述的不在不变代码集合内,该集合是七位美国 ASCII 代码集合的子集的字符。
ErrorHasOccurred() && HandleError();
。 - Yam Marcovic一般来说,为什么这个存在的原因可能与它在你的例子中存在的原因不同。
事情始于半个世纪前,通过将硬拷贝通信终端重新用作计算机用户界面。 在最初的Unix和C时代,ASR-33 Teletype是这样一个设备。
该设备速度慢(10 cps),嘈杂且难看,并且其ASCII字符集的视图仅限��0x5f,因此它没有(仔细查看图片)任何键:
{ | } ~
三字符组(trigraphs)的定义是为了解决一个具体的问题。想法是C程序可以使用ASR-33和其他环境中缺少高ASCII值的ASCII子集。
你的示例实际上是两个
??!
,每个都表示|
,因此结果是||
。
然而,写C代码的人基本上都有现代设备,1所以我猜测:这是某个人在展示或自娱自乐,留下了一种彩蛋让你去发现。
确实奏效了,它引起了一个非常受欢迎的SO问题。
ASR-33 电传打字机
#
被替换为 £
。在其他地区,也许 "ASCII" 没有花括号等符号。 - user180247if (x || y) { a[i] = '\0'; }
看起来像在错误的字符集中写成 if (x öö y) ä aÄiÅ = 'Ö0'; å
的情况。 - Ilmari Karonen这是一个C语言的三字符组。 ??!
代表|
,因此??!??!
表示逻辑运算符||
<iso646.h>
头文件。 - David R Tribble如前所述,??!??!
本质上是两个 三字符组合(再次出现的 ??!
和 ??!
)被拼接在一起并由预处理器替换为 ||
,即逻辑或。
下表列出了每个三字符组合,有助于消除其他三字符组合的歧义:
Trigraph Replaces
??( [
??) ]
??< {
??> }
??/ \
??' ^
??= #
??! |
??- ~
来源:C语言参考手册第五版
因此,类似于??(??)
的三字符序列最终会映射为[]
,??(??)??(??)
将被替换为[][]
等等,你明白了。
由于三字符序列在预处理期间被替换,您可以使用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没有提供其他语言所需的一些字符,因此制作了一些国家变体,用所需的字符替换了一些不常用的字符。
(我强调的)
因此,在某些国家变体中,一些所需字符(存在三字符标识符)被替换。这导致使用由其他变体仍然具有的字符组成的三字符标识符的替代表示。
char *date = "??-??-??"
这样的占位符可能不会产生您所期望的结果(实际上会产生 char *date = "~~|";
)。 - Andrewif(data??(x??)??(y??)=='??/r' ??!??! data??(x??)??(y??)==0) ??< break; ??>
- wojtow?:
就可以提高可读性。 - quetzalcoatl