web-dev-qa-db-ja.com

Cは何をしますか。演算子はありますか?

このようなCの行を見ました。

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

正しくコンパイルされ、正常に動作しているようです。エラーが発生したかどうかをチェックしているようで、発生した場合はそれを処理します。しかし、それが実際に何をしているのか、またはそれがどのようにして行っているのかはよくわかりません。プログラマがエラーについての自分の気持ちを表現しようとしているように見えます。

私はこれまでにどのプログラミング言語でも??!??!を見たことがなく、それに関する文書もどこにもありません。 (Googleは??!??!のような検索用語には役立ちません)。それは何をしていて、コードサンプルはどのように機能しますか?

1820
Peter Olson

??!trigraph で、これは|に変換されます。だからそれは言う:

!ErrorHasOccured() || HandleError();

これは、短絡のため、次のものと同等です。

if (ErrorHasOccured())
    HandleError();

今週のグル (C++を扱うがここでは関連がある)、これを拾ったところ。

3文字表記の起源 または@DwBがコメントで指摘しているように、EBCDICが(再び)難しいことが原因である可能性が高い。 これ //IBM developerworksの掲示板での議論は、その理論を支持しているようです。

ISO/IEC 9899:1999§5.2.1.1、脚注12(h/t @ Random832)から。

3文字シーケンスは、7ビットのUS ASCIIコードセットのサブセットであるISO/IEC 646で説明されているように、不変コードセットで定義されていない文字の入力を可能にします。

1475
user786653

さて、これが一般的に存在する理由は、おそらくそれがあなたの例に存在する理由とは異なるでしょう。

それはすべて半世紀前にハードコピー通信端末をコンピュータユーザインタフェースとして再利用することから始まった。初期のUnixとCの時代には、ASR-33テレタイプでした。

このデバイスは遅く(10 cps)、うるさくて醜く、ASCII文字セットの表示は0x5fで終わっていたので、(写真をよく見て)キーはありませんでした。

{ | } ~ 

三文字表記 は特定の問題を解決するために定義された。その考えは、CプログラムがASR-33に見いだされるASCIIサブセットを使うことができ、そして他の環境では高いASCII値を欠いているということでした。

実際の例は、実際には2つの??!です。それぞれが|を意味するので、結果は||です。

しかし、ほぼ定義どおりにCコードを書いている人は近代的な装置を持っていました、1 それで私の推測は:誰かが自慢したり面白くしたりするあなたが見つけることができるようにコードに一種のイースターエッグを残すこと。

それは確かにうまくいった、それは大流行のSO質問を導いた。

ASR-33 Teletype

ASR-33テレタイプ


1.その点に関して、最初にafter Cに出会ったトライグラフはANSI委員会によって発明されたので、元のCコードやコーダーはそれらを使用しませんでした。
414
DigitalRoss

それはC trigraph です。 ??!|なので、??!??!は演算子||です。

153
Joel Falcou

すでに述べたように、??!??!は本質的に2trigraphs??!??!である)プリプロセッサによって||、つまり 論理OR に置き換えられて変換されるマッシュアップ。

すべてのトライグラフを含む次の表は、代替のトライグラフの組み合わせを明確にするのに役立ちます。

Trigraph   Replaces

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

出典:C:リファレンスマニュアル第5版

したがって、??(??)のように見えるトライグラフは、最終的に[]にマップされ、??(??)??(??)[][]に置き換えられます。

前処理中にトライグラフが置換されるため、 cpp を使用して、愚かなtrigr.cプログラムを使用して、出力のビューを自分で取得できます。

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

そしてそれを次のように処理します:

cpp -trigraphs trigr.c 

次のコンソール出力が得られます

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

お気づきのとおり、オプション-trigraphsを指定する必要があります。指定しないと、cppが警告を発行します。これは、トリグラフが過去のものであり、衝突する可能性のある人を混乱させること以外の現代的な価値がないことを示しています


3文字表記の導入の根拠については、 ISO/IEC 646の履歴セクション

ISO/IEC 646およびその前身であるASCII(ANSI X3.4)は、電気通信業界の文字エンコーディングに関する既存の慣行をほぼ支持しました。

ASCIIは英語以外の言語に必要な文字数を提供していなかったため、いくつかのより少ない代替文字を使用した国別のバリエーションがいくつか作成されました。必要なものと使用された文字

(エンファシス鉱山)

そのため、本質的に、一部の必要な文字(トライグラフが存在する文字)は、特定の国のバリアントで置き換えられました。これは、他のバリアントがまだ持っていた文字で構成されるトライグラフを使用した代替表現につながります。

133