2015年11月5日木曜日

Cのトライグラフ表記

こんにちは、綱島です。


先日、メインフレームやWindowsなど、異なるプラットフォーム上で動作するソフトウェアのソースを見る機会がありました。
そのソースを見たとき、なんだこれは?
C言語のソースと聞いていたのに、なんだか知らない表記があるけど。。。

それが、トライグラフという表記方法でした。
恥ずかしながら、二十年以上C言語に携わってきましたが、私は初耳でした。

下のソースを見てください。

#include <stdio.h>

static char tric[9][4] = {
    { '?', '?', '=', NULL },
    { '?', '?', '(', NULL },
    { '?', '?', '/', NULL },
    { '?', '?', ')', NULL },
    { '?', '?', '\'', NULL },
    { '?', '?', '<', NULL },
    { '?', '?', '!', NULL },
    { '?', '?', '>', NULL },
    { '?', '?', '-', NULL }};

static char *tri[9] = {
    "??=",
    "??(",
    "\??/",
    "??)",
    "??'",
    "??<",
    "??!",
    "??>",
    "??-" };

void main( int argc, char *argv??(??) );

void main( int argc, char *argv[] ) {

    for ( int i = 0; i < 9; i ++ ) {
        printf( "%s - %s\n", tric[i], tri[i] );
    }
}

このソースのprintfの出力結果はどうなるでしょうか?
ハイフンの左右文字列は同じでしょ?と思われた方も多いと思います。
いやいや、その前にプロトタイプ宣言がコンパイルエラーでは?と思うかもしれません。
そんなことはなく、コンパイルもできて、実行結果はこうなります。

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

左側は、各文字そのままですが、右側は違う文字になっていますね。
左側が右側の文字をトライグラフで表記したものになります。
これは、ISO646(ASCIIを国際化した規格)の文字のうち、国などで変わる文字以外C言語を表記するためだそうです。

そういえば、このトライグラフを使って書かれたソースを見たのは、メインフレームでした。
メインフレームで使用しているEBCDICコードは、コード体系にもよりますが、C言語で頻繁に使用される"["、"]"(ブラケット)がありません。そのため、トライグラフを使って表記していたようです。
書かれた時代も古かったし、メインフレームで使用していたコンパイラーはSAS-Cというコンパイラーでしたので、半信半疑でVisual C++でコンパイルしてみましたが、ちゃんとコンパイルできました。
なお、コンパイラーやバージョンによっては、オプションで有効/無効の切り替えが必要な場合もあるようです。


処理順位ですが、""内でも変換されることでお分かりのように、コンパイル処理では一番最初に処理されるようです。
そのため、上記ソースのtri[2]には、「\」が必要なんです。最初このソース書いたとき、なんでコンパイルエラーなのかと、子一時間悩みました。理由はわかりますよね?先に、「??/」が変換されて、「"\",」となり、「\」はエスケープ文字として処理されますからね。


突然、C言語で「??」が現れたとき、あせらずにこの記事を思い出してください。

0 件のコメント:

コメントを投稿