我看到一行C,看起来像这样:
1
| !ErrorHasOccured() ??!??! HandleError(); |
它编译正确,运行正常。它似乎在检查是否发生了错误,如果发生了错误,它就会处理它。但我不太确定它到底在做什么,它是如何做的。看起来程序员确实在试图表达他们对错误的感受。
我以前从未见过任何编程语言中的??!??!,而且在任何地方都找不到它的文档。(谷歌对像??!??!这样的搜索词没有帮助)。它做什么,代码示例如何工作?
- 用另一种方式表达你的情绪,不要使用三角图,写一些人类可以理解的代码。
- @彼得罗森,你希望!ErrorHasOccurred() ??!???! HandleError();如何编译?那是??!???!。证明了这一点?
- 我建议你仔细阅读干净的密码。ErrorHasOccured()应重构为ErrorHasNotOccured(),从而清除感叹号…谁有时间理解所有这些运算符??!
- 我更喜欢我自己。Lua也是这么做的。
- @Kadekm,将否定移动到函数名中并不能得到干净的代码,相反。
- 即使在今天,我也能真正使用三角图:当某段代码真正工作时,你可以增加没有人试图重写/优化/使代码失效的可能性。确实,这是一个非常有限的优势。
- "读干净的代码"是的,当然,因为这不是一个完全有争议和主观的话题,你可以为它写一个食谱。
- 最著名的是"WTF运营商"
- 对于任何一个在用他们的搜索引擎进行了一场殊死搏斗后来到这里的人来说,一条注释是:符号猎犬可以帮助进行象征性的搜索。
- 遗憾的是,这个程序的宝石在C++ 17和更新版中是行不通的。
- 意思是"或"…
??!是一个转换为|的三角图。所以它说:
1
| !ErrorHasOccured() || HandleError(); |
由于短路,相当于:
1 2
| if (ErrorHasOccured())
HandleError(); |
本周的Guru(处理C++,但这里相关),在这里我选择了这一点。
可能是三角图的起源,或者正如@dwb在评论中指出的那样,它更可能是由于EBCDIC比较困难(再次)。关于IBMdeveloperWorks板的讨论似乎支持这一理论。
根据ISO/IEC 9899:1999第5.2.1.1节脚注12(h/t@random832):
The trigraph sequences enable the input of characters that are not defined in the Invariant Code Set as
described in ISO/IEC 646, which is a subset of the seven-bit US ASCII code set.
- 如果您的键盘没有""符号,最初需要使用三角图。在这里,要么是程序员故意让人恼火,要么是某个奇怪的编辑"特性"
- 那么它是依赖于EDOCX1[0]短路还是什么?
- 是的,相当于if (ErrorHasOccured()) HandleError()。谢天谢地,您通常只在Perl代码中遇到这个习语。
- @彼得罗森-正确。如果!ErrorHasOccured()解析为true则短路,否则调用HandleError()。
- 为EBCDIC计算机添加了三角图。
- @用户786653:即使在Perl中,这肯定就是unless的目的吗?
- @史蒂文杰索普:我不是想支持它。这正是我最常看到的地方,例如open(...) or die(...)。
- 它不一定是EBCDIC——需要三角图的字符集几乎完全匹配ISO-646中不不变的字符集(即旧的"国家ASCII"标准)。
- @random832:该标准有一个脚注说:三角图序列允许输入未在不变代码集中定义的字符,如ISO/IEC 646所述,后者是7位US ASCII代码集的一个子集。
- 德国和瑞典的变体在该代码位置有字母"&246;"。
- 一个完全可读的替代方案是ErrorHasOccurred() && HandleError();,也就是说,如果您习惯于shell脚本编写。:)
- 任志刚所说的(仅在我的情况下,用"ruby"替换"shell")。
- 停止编译器决定首先执行对handleError()的调用是什么?
- 布尔运算符被严格评估为ltr、iirc。
- 请注意,许多编码标准都专门禁止使用三角图和有向图,许多编译器和静态分析器都会标记它们的使用。
- 我还是看不懂那个:!errorhasoccured()handleerrror();-用普通英语怎么读?如果有错误或处理错误?-如果有错误,或者你可以处理错误,是吗?
- 读作"要么没有错误,要么你必须处理错误",@sparkyrobinson。
- @用户786653在Perl中,写:handleError() if errorHasOccured()或类似于handleError() unless isSuccess()的东西会更有表现力。
- @SparkyRobinson在其状态下读取:(未发生错误)或(处理错误)。
- 有向图上的man cobfusc:只有少数C编译器(BSD 2001年7月1日)支持对ansi x3.159-1989("ansi c89")的修改1(1994年)。
- IBM线程链接已断开。你能换一个吗?
- 无效,因为C++ 17:
好吧,一般来说,为什么会存在这一点可能与为什么它会存在于您的示例中不同。
这一切都始于半个世纪前,将硬拷贝通信终端重新用作计算机用户界面。在最初的Unix和C时代,这是ASR-33电传打字机。
该设备速度慢(10 cps),噪音大,外观难看,ASCII字符集的视图以0x5F结尾,因此(仔细看图片)没有任何键:
三角图被定义为解决一个特定的问题。其想法是,C程序可以使用ASR-33和其他缺少高ASCII值的环境中的ASCII子集。
Your example is actually two of ??!, each meaning |, so the result is ||.
然而,写C代码的人几乎都有现代的设备,所以我的猜测是:有人在代码中炫耀或取笑自己,留下一个复活节彩蛋给你找。
它确实起作用了,它引出了一个非常流行的问题。
&ASR-33电传打字机1。就这一点而言,三角图是由美国国家标准协会委员会发明的,该委员会在C取得巨大成功后首次开会,因此原始的C代码或编码人员都不会使用它们。
- 这并不是键盘和字符集中唯一缺少字符的情况。对于很多三十多岁的人来说,64准将可能更为熟悉——显示的字符集都缺少大括号(也可能缺少大括号和颚化符)——在这种情况下,因为"ascii"不是ascii。在ECMA-6(几乎总是称为ASCII,但不是US-ASCII)中,有18个特定于区域的代码,但我不知道它们是什么代码。我可以肯定的是,在英国的"ASCII"中,#被£取代。在其他地区,"ascii"可能没有大括号等。
- 类似的Atari 8位计算机的Atascii字符集也缺少和`。
- 看看这两篇维基百科文章。我已经差不多大了,还记得7位国家字符集的时代(尽管我确信它们仍然停留在一些黑暗的、无穷无尽的角落里),我第一次学习C的那本书发现,有必要警告if (x || y) { a[i] = '\\0'; }在错误的字符集中看起来像if (x öö y) ä aÄiÅ = 'Ö0'; å的可能性。
- @史蒂文314:好吧,在C64上,你可以重写字符集,这样你就可以使用你喜欢的任何编码:)
- 另一个有趣的历史记录是,Unix(它是C所使用的大型平台)可能是第一个将字母值默认为小写而不是大写的系统,具有任何意义(并且可能是第一个整体)。虽然我没有亲眼看到许多当代的系统,但我认为这是一个成熟的真正标志。除了真正的正派操作系统之外,Unix还将大写字母转换为小写字母,而不是相反。那些人真的很酷。
- 有趣的故事我要告诉你…IBM RS/6000工作站的XL Fortran编译器是从XLC编译器开发的。在最初的几个版本中,它们意外地留在了三角图处理中,所以有一些合法的Fortran字符序列(在文本字符串中,IIRC)被错误地解释为C三角图,导致了一些有趣的错误!
- @DigitalRoss:我知道准将后来来了,但是大小写是默认的还是默认的取决于选择的字符集。此外,屏幕字符代码与内核中"getch/putch"等效方法使用的代码之间的关系相当奇怪。苹果电脑的Putch相当于使用了屏幕代码,它的第7位设置为正常文本。此外,在为//e释放80列卡之前,即使可以显示小写的机器也只能在非反转文本中执行此操作。
- @史蒂文314:如果你想用精确的代码刷新你的记忆,ECMA-6标准可以在线使用:)
- 这是一个很好的答案,但看起来0右边的键实际上是一个|键(上面有*键)。
- @gus——这实际上是一个:——这里有更好的图片:pdp8.net/asr33/pic s/kbd-top.shtml?大的
- 我喜欢……重新…转
- 三角图很恐怖。唯一需要在带引号的字符串中合成的字符是反斜杠("meta")字符,如果文件的第一行只包含一个字符,而该字符不是反斜杠或不在C字符集中,编译器应该将该字符视为meta c从那时起。所有其他字符都可以作为"反斜杠"转义符使用。不了解此功能的编译器只会忽略包含反斜杠的行,而不忽略其他行。
- 我听过一个C90委员会成员的轶事,那就是到了ISO标准化的时候,他们仍然不能排除三角图。问题是,一些语言(例如北欧语言和德语)的键盘仍然缺少各种外来符号,如|、{等,为了获得字母表中所有字母的键而牺牲了这些符号。
这是一个C三角。??!是|,所以??!??!是||的运算符。
- 为什么要有人使用??!而不是????/
- 三角图来自一个时期,有些键盘没有所有的键,他们现在。它还帮助一些文本编辑器为特殊的事情保留特殊字符。它主要是过去的遗物和一个智力测验的推动者;)
- 因为有些键盘显然没有"",所以有些人别无选择,只能反复用头碰键盘,直到出现一个三角图,给他们所需要的符号。
如前所述,??!??!基本上是两个三角形(??!和??!再次混合在一起,被替换为||的,即逻辑或,由预处理器。
下表包含每个三线图应有助于消除交替三线图组合的歧义:
1 2 3 4 5 6 7 8 9 10 11
| Trigraph Replaces
??( [
??) ]
??< {
??> }
??/ \\
??' ^
??= #
??! |
??- ~ |
资料来源:C:A参考手册第5版
因此,一个看起来像??(??)的三角图最终将映射到[],??(??)??(??)将被[][]替换,依此类推,你就知道了。
由于在预处理过程中替换了三角图,因此可以使用cpp自己查看输出,使用一个愚蠢的trigr.c程序:
1
| void main(){ const char *s ="??!??!"; } |
并通过以下方式进行处理:
您将获得控制台输出
1
| void main(){ const char *s ="||"; } |
正如您所注意到的,必须指定选项-trigraphs,否则cpp将发出警告;这表明了三角图是如何成为过去的事物,除了可能会碰到它们的混淆者之外,没有现代价值。
至于引入三角图背后的基本原理,在查看ISO/IEC 646的历史部分时可以更好地理解:
ISO/IEC 646 and its predecessor ASCII (ANSI X3.4) largely endorsed existing practice regarding character encodings in the telecommunications industry.
As ASCII did not provide a number of characters needed for languages other than English, a number of national variants were made that substituted some less-used characters with needed ones.
(强调矿山)
因此,在本质上,一些需要的字符(有一个三角图的字符)被某些国家变体所取代。这就导致了使用由其他变体仍然存在的字符组成的三角图的替代表示。