2237

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

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

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

どのプログラミング言語でも見た??!??!ことがなく、ドキュメントもどこにもありません。(Google は のような検索用語には対応していません??!??!)。それは何をし、コード サンプルはどのように機能しますか?

4

4 に答える 4

1777

??!に変換されるトライグラフ|です。だからそれは言います:

!ErrorHasOccured() || HandleError();

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

if (ErrorHasOccured())
    HandleError();

Guru of the Week (C++ を扱いますが、ここに関連があります)、ここでこれを取り上げました。

トライグラフの起源の可能性、または @DwB がコメントで指摘しているように、EBCDIC が困難であることが原因である可能性が高くなります (再び)。IBM developerworks ボードでのこの議論は、その理論を支持しているようです。

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

トライグラフ シーケンスを使用すると、7 ビットの US ASCII コード セットのサブセットである ISO/IEC 646 で説明されているように、不変コード セットで定義されていない文字を入力できます。

于 2011-10-19T16:58:44.797 に答える
518

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

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

このデバイスは低速(10 cps)で、ノイズが多く醜く、ASCII文字セットの表示は0x5fで終了したため、(写真をよく見て)キーがありませんでした。

{ | } ~ 

三重音字は、特定の問題を修正するために定義されました。Cプログラムは、ASR-33やその他の環境で拡張ASCII値が欠落しているASCIIサブセットを使用できるという考えでした。

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

しかし、ほぼ定義上、Cコードを書いている人は最新の機器を持っていたので1、私の推測では、誰かが自分を見せびらかしたり、楽しんだりして、コードにイースターエッグのようなものを残して見つけてもらいます。

それは確かに機能しました、それは非常に人気のあるSOの質問につながりました。

ASR-33テレタイプ

                                            ASR-33テレタイプ


1.さらに言えば、トリグラフはANSI委員会によって発明されました。この委員会は、 Cが暴走したに最初に会合したため、元のCコードやコーダーはそれらを使用していませんでした。

于 2011-10-19T21:09:06.257 に答える
188

C trigraphです。??!です、演算子|もそうです??!??!||

于 2011-10-19T16:58:56.063 に答える
176

すでに述べたよう??!??!に、基本的には 2 つのトリグラフ(??!および??!再び) が一緒にマッシュアップされ、プリプロセッサによって に置換変換されます||。つまり、論理 ORです。

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

Trigraph   Replaces

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

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

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

トリグラフは前処理中に置換されるため、ばかげたプログラム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 は英語以外の言語に必要な文字数を提供しなかったため、使用頻度の低い文字を必要な文字に置き換えた多くの各国語のバリエーションが作成されました

(私のものを強調)

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

于 2016-03-25T02:24:53.770 に答える