这是什么?????!运算符在C中做什么?

发布于 2024-12-10 16:42:32 字数 309 浏览 0 评论 0原文

我看到一行 C 代码,如下所示:

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

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

我以前从未在任何编程语言中见过 ??!??! ,而且我在任何地方都找不到它的文档。 (Google 不支持像 ??!??! 这样的搜索词)。它有什么作用以及代码示例如何工作?

I saw a line of C that looked like this:

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

It compiled correctly and seems to run ok. It seems like it's checking if an error has occurred, and if it has, it handles it. But I'm not really sure what it's actually doing or how it's doing it. It does look like the programmer is trying express their feelings about errors.

I have never seen the ??!??! before in any programming language, and I can't find documentation for it anywhere. (Google doesn't help with search terms like ??!??!). What does it do and how does the code sample work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦幻的味道 2024-12-17 16:42:32

??! 是一个 三字母,转换为 |。所以它说:

!ErrorHasOccured() || HandleError();

由于短路,相当于:

if (ErrorHasOccured())
    HandleError();

本周大师 (涉及 C++,但与这里相关),我在那里找到了这个。

三字母组的可能起源 或者@DwB 在评论中指出,这更有可能是由于 EBCDIC 很困难 (再次)。 <一href="https://web.archive.org/web/20191226092436/https://www.ibm.com/developerworks/community/论坛/html/topic?id=77777777-0000-0000-0000-000014505842#77777777-0000-0000-0000-000014505849" rel="noreferrer">IBM Developerworks 板上的这个讨论似乎支持了这一理论。

来自 ISO/IEC 9899:1999 §5.2.1.1,脚注 12 (h/t @Random832):

三字母序列允许输入未在不变代码集中定义为的字符
ISO/IEC 646 中描述,它是七位 US ASCII 代码集的子集。

??! is a trigraph that translates to |. So it says:

!ErrorHasOccured() || HandleError();

which, due to short circuiting, is equivalent to:

if (ErrorHasOccured())
    HandleError();

Guru of the Week (deals with C++ but relevant here), where I picked this up.

Possible origin of trigraphs or as @DwB points out in the comments it's more likely due to EBCDIC being difficult (again). This discussion on the IBM developerworks board seems to support that theory.

From ISO/IEC 9899:1999 §5.2.1.1, footnote 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.

伴我心暖 2024-12-17 16:42:32

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

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

该设备速度缓慢(10 cps)、嘈杂且丑陋,其 ASCII 字符集视图以 0x5f 结束,因此(仔细观察图片)没有任何键

{ | } ~ 

: codingstandard.com/rule/2-2-1-do-not-use-digraphs-or-trigraphs/" rel="noreferrer">三字母的定义是为了解决特定问题。这个想法是,C 程序可以使用 ASR-33 上以及其他缺少高 ASCII 值的环境中找到的 ASCII 子集。

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


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

它确实有效,它引发了一个广受欢迎的SO问题。

ASR-33电传打字机

                                 ASR-33电传打字机


1. For that matter, the trigraphs were invented by the ANSI committee, which first met after C become a runaway success, so none of the original C code or coders would have used them.

Well, why this exists in general is probably different than why it exists in your example.

It all started half a century ago with repurposing hardcopy communication terminals as computer user interfaces. In the initial Unix and C era that was the ASR-33 Teletype.

This device was slow (10 cps) and noisy and ugly and its view of the ASCII character set ended at 0x5f, so it had (look closely at the pic) none of the keys:

{ | } ~ 

The trigraphs were defined to fix a specific problem. The idea was that C programs could use the ASCII subset found on the ASR-33 and in other environments missing the high ASCII values.

Your example is actually two of ??!, each meaning |, so the result is ||.

However, people writing C code almost by definition had modern equipment,1 so my guess is: someone showing off or amusing themself, leaving a kind of Easter egg in the code for you to find.

It sure worked, it led to a wildly popular SO question.

ASR-33 Teletype

                                            ASR-33 Teletype


1. For that matter, the trigraphs were invented by the ANSI committee, which first met after C become a runaway success, so none of the original C code or coders would have used them.

染墨丶若流云 2024-12-17 16:42:32

如前所述 ??!??! 本质上是两个 三字母??!??! 再次)混合在一起,被替换翻译为 ||,即逻辑或,由预处理器执行。

包含每个三字母组合的下表应有助于消除替代三字母组合的歧义:

Trigraph   Replaces

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

来源:C:参考手册第五版

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

由于在预处理过程中三字母被替换,您可以使用 cpp自己查看输出,使用一个愚蠢的 trigr.c 程序:

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

并使用以下方法处理它:

cpp -trigraphs trigr.c 

您将获得控制台输出 正如

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

您所注意到的,选项 -trigraphs< /code> 必须指定,否则cpp 会发出警告;这表明三字母已经成为过去,除了让可能遇到它们的人感到困惑之外,没有任何现代价值。


至于引入三字母组合背后的基本原理,通过查看历史部分可以更好地理解ISO/IEC 646

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

由于 ASCII 没有提供英语以外的语言所需的大量字符,产生了许多国家变体,用所需的字符替换了一些较少使用的字符 .

(强调我的)

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

As already stated ??!??! is essentially two trigraphs (??! and ??! again) mushed together that get replaced-translated to ||, i.e the logical OR, by the preprocessor.

The following table containing every trigraph should help disambiguate alternate trigraph combinations:

Trigraph   Replaces

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

Source: C: A Reference Manual 5th Edition

So a trigraph that looks like ??(??) will eventually map to [], ??(??)??(??) will get replaced by [][] and so on, you get the idea.

Since trigraphs are substituted during preprocessing you could use cpp to get a view of the output yourself, using a silly trigr.c program:

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

and processing it with:

cpp -trigraphs trigr.c 

You'll get a console output of

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

As you can notice, the option -trigraphs must be specified or else cpp will issue a warning; this indicates how trigraphs are a thing of the past and of no modern value other than confusing people who might bump into them.


As for the rationale behind the introduction of trigraphs, it is better understood when looking at the history section of 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.

(emphasis mine)

So, in essence, some needed characters (those for which a trigraph exists) were replaced in certain national variants. This leads to the alternate representation using trigraphs comprised of characters that other variants still had around.

天煞孤星 2024-12-17 16:42:32

这是一个 C 三字母??!|,因此 ??!??! 是运算符 ||

It's a C trigraph. ??! is |, so ??!??! is the operator ||

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文