IOCCCコード解析その2

ちわっす!

局地的豪雨によりずぶぬれになること既に3回。やってらんね〜いつも家に帰る途中なんで傘を購入せずに帰ろうとするからずぶぬれになるんですけどね。周りから見ると変なのかな〜と最近思うようになってきた。そんな事はほっといて・・・

・1986年 「Most adaptable program」受賞作品(applin.c)

 cat =13 /*/ >/dev/null 2>&1; echo "Hello, world!"; exit
*
* This program works under cc, f77, and /bin/sh.
*
*/; main() {
write(
cat-~-cat
/*,'(
*/
,"Hello, world!"
,
cat); putchar(~-~-~-cat); } /*
,)')
end
*/
なんだか少しまともそうなコードですね。「Most adaptable program」ってどういう意味?翻訳してみたけど「最も融通のきくプログラム」だって、ふ〜んだね。処理の内容としては「Hello, world!」を画面に出力しているのだろう。
と言うわけで最初に余分なコメントを削除し整形してみた。
cat =13;
main() {
write(cat-~-cat, "Hello, world!", cat);
putchar(~-~-~-cat);
}
ずいぶんとすっきりした。もう読めたも同然じゃね!まあ〜残る問題は猫ちゃんだろう。この部分、
write(cat-~-cat, "Hello, world!", cat);
システムコールだね。cat = 13 だから13byte出力するってのはわかる。文字列も13byteだし、じゃあどこに出力ってことだ。
cat-~-cat
ん〜c言語演算子で「~」なんてものがあるんだ。これは補数演算子って言うらしい、へ〜だね。
何をするかと言えばビット単位で反転するもの(例:0110->1001)ふ〜んな感じかな。
cat-~-cat
===>13-~-13===>1101-~(-1101)===>1101-(~0011)===>1101-1100===>0001===>1
上記のような変換ができるんでないの?えっとね数値の前にマイナス符号があると思うんだけど、これは2の補数を取ってみたよ。
なぜ2の補数なのかって?それは勘なの。
write(cat-~-cat, "Hello, world!", cat);
===>write(1, "Hello, world!", 13); となり標準出力に文字列"Hello, world!"から13byte出力せよって事だよね。

putchar(~-~-~-cat);
最後に残ったこれも同じようにやる
~-~-~-cat
===>~-~-~-13
===>~-~-~(-1101)
===>~-~-(~0011)
===>~-~(-1100)
===>~-(~0100)
===>~(-1011)
===>~0101
===>1010
===>10
最終的に10という数値が出てきた。
putchar(~-~-~-cat);
===>putchar(10);
ASCIIコードで10は改行を表しているので、文字列出力後、改行を出力しているって事かな。
ん〜これで「Hello, world!」が出力された。実際にコンパイル後、実行してみると画面に「Hello, world!」と表示されるし改行もあるね〜あんまり読みにくくなかったよ。ポイントは「~-」ってやつかな、ちょっと悩んだけど勘が働いた。一応、デバッガ動かしてみて数値確認したんで問題ないと思う。うん、大丈夫なはず。
ちなみにコードの頭付近、cat = 13 の直後に続くshellスクリプトみたいなもの、あれで見た人を幻惑させようとの魂胆かもしれないがコメントなんでバッサリとカットね。
以上

追記。
私があさはかでした〜。実力不足ですね〜このソースファイルを実行すると面白い事に「Hello, world!」と表示される。凄いね〜

cat =13 /*/ >/dev/null 2>&1; echo "Hello, world!"; exit
の部分がshellスクリプトとして実行されるんですよね。「cat =13」だけならエラーが出力されるんですけど、「>/dev/null」が全部吸収しているのかな〜で画面に表示して「exit」をして終了。ちょっと驚いた。

ではでは