C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

うさぎさんはトライグラフを使った!! → わけがわからなくなった

別に使う必要に迫られた訳では無いのですが、"トライグラフ"というものを使ったあるプログラミング言語ソースコードのごく初歩的で簡単なコードのサンプルがこちらになります。

??=include <iostream>
int main()??<
  unsigned a??(??)=??<1,2,3??>;
  std::cout<<??-((a??(0??)??!a??(1??))-a??(2??));
??>

"あるプログラミング言語"と言いましたがどう見てもC++な気はしますね?C++です。しかしまるで難読化されたかの様な難解なコードに見えますね?実は簡単です。

このコードをGCC-4.7.1/openSUSE-12.2(x86_64)で実行まですると、

4294967295

と表示されます。(42じゃない点はご了承下さい)

実は先のコードはC++規格でもしっかり定義されている"トライグラフ"(§2.4 Trigraph sequence)という機能を使ってコードしたもの。同じソースをトライグラフを使わずにコードすると次の通り。これは最初に示したコードと完全に等価にコンパイラーに評価されます。

#include <iostream>
int main(){
  unsigned a[]={1,2,3};
  std::cout<<~((a[0]|a[1])-a[2]);
}

こうなると誰でもわかりますね・w・;

最終的には処理系依存のunsigned型の最大値を表示しているだけです。0xFFFFFFFFとかをね。その計算も何て言う事は無く1と2のOR(|)、つまり3、そこから3を引いて0、それにNOT(~)をしているというちょっとしたナンセンス。しかしこれがトライグラフなるものを使うと先の通り難読化される。勿論トライグラフは難読化の為にある機能ではなく、 # \ ^ [ ] | { } ~ の9つの記号の入力が困難な環境でもC++ソースコードを記述できるように、 ??X の形式の3文字でひと固まりと見做すトライグラフ(tri-graph; 意訳:3つなる文字)を定義していた、というやや神話の時代になりつつあるような昔話から現代に受け継がれ続けている言語仕様だったりします。

…少なくとも日本ではトライグラフを必要とする様な環境には遭遇しませんね。ASCIIを扱える環境は問題になりませんから、大昔の文字コード固定の汎用機時代の遺物なんでしょうかねー…。さすがに私は生で汎用機を使っていた時代ではないので本当かまでは知りませんけれど。

// ちなみにC++の言語仕様書しか読んで居ないのでANSIに追加された経緯だとかそれはCプリプロセッサーのとかEBCDIC文字コードとか気になる人は調べたらいいと思うよ・x・