世界一変なプログラムコード

IOCCC(国際邪悪なCコードコンテスト)

Perlについて調べてリンクを辿っていたらこんな記事を見つけた。
http://ja.wikipedia.org/wiki/IOCCC
記事より引用

IOCCCとは「The International Obfuscated C Code Contest(国際邪悪なCコードコンテスト)」の略称。汚く読みづらいC言語コードをあえて書き、その汚さを競うというC言語ハッカーの奇祭である。

  • 1987年「Best One Liner」受賞作、David Korn作。
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}

説明:一見コンパイルが通らないように見えるが、上記コードは正常にコンパイルされ、実行すると「unix」と表示される。UNIX上でコンパイルした場合トークunixが1としてマクロ定義(#define unix 1)されており、配列要素のアクセス方法で配列と添字が交換可能であることなどのテクニックを利用している。

コードだけ見ても何やってるのか訳が分からないが、答えをヒントに処理を推測してみた結果、仕組みがようやく理解できた。

しかし、常日頃から分かりやすいプログラムを書く事ばかり心がけてきたため、いきなり真似しようと思っても中々アイデアが出て来ない。
こういう遊びを楽しむためには、もっとプログラムにのめり込む必要があるのかも知れない。

コードの解読

まず、unixを1に置き換える。

main() { printf(&1["\021%six\012\0"],(1)["have"]+"fun"-0x60);}

文字列と添字を入れ替える。

main() { printf(&"\021%six\012\0"[1],"have"[1]+"fun"-0x60);}

"have"から文字'a'を取り出す。

main() { printf(&"\021%six\012\0"[1],'a'+"fun"-0x60);}

文字'a'を16進コードで表す。

main() { printf(&"\021%six\012\0"[1],0x61+"fun"-0x60);}

16進数同士を計算する。

main() { printf(&"\021%six\012\0"[1],"fun"+1);}

数値1は"fun"の添字になり、"fun"自体は文字列"fun"の先頭アドレスを指すので、&を付ける。

main() { printf(&"\021%six\012\0"[1],&"fun"[1]);}

文字列[添字]は、添字+1文字目になり、&を付ける事でそのアドレスを指し示す。つまり、先頭1文字をカットした次の表記と同じ意味になる。(¥021は文字コード0x11と同じ意味になり、1文字分のデータとなる。制御文字だが、カットするので関係ない。)

main() { printf("%six\n","un");}

printfの書式に従い、文字を置き換える。

main() { printf("unix\n");}