- ベストアンサー
C言語の超難解なプログラムについて
WikiのIOCCCのページに書いてあるプログラムで以下のようなプログラムがありました。 main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);} このプログラムがどのような過程でどのように動いているのかを詳しく知りたいです。 プログラムに詳しい方よろしくお願いします。 IOCCCのページ http://ja.wikipedia.org/wiki/IOCCC
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
あまり考えたくないもろもろの抜け道で動いてます(笑) 順番に書き換えましょう。 まず、引数の一つ目の式。 &unix["\021%six\012\0"] この式において、unixは、1と定義されています。(デフォルトのプリプロセッサマクロです。) &1["\021%six\012\0"] となります。 さて、C言語の配列とアドレス演算の表記の問題です。 a[b]という表現は、*(a+b)と等価です。*(a+b)は、*(b+a)と等価です。最後の式を配列表現に戻すと、b[a]となります。ですから、a[b]とb[a]は等価です。 文字列リテラルは、書き換え不可の領域に格納された配列の一表現形式です。文字列リテラルは配列として扱えます。"abcde"[1]は、'b'です。 さて、ですから、問題の式は、次のように書き換え可能です。 &"\021%six\012\0"[1] 添え字が1ですから、二文字目のアドレスを渡していることになりますので、第一引数を人間向きに書き直すと、次のようになります。 "%six\012\0" ちなみに、\012は、8進数表記ですが、文字コード表を見ると、\nです。 "%six\n\0" 今、元のコードは、次のようになっています。 main() { printf("%six\n\0",(unix)["have"]+"fun"-0x60);} さて、第2引数に行きましょう。 unixは、1と置き換えますから、 1["have"]+"fun"-0x60 配列の表記を逆にして、 "have"[1]+"fun"-0x60 ここで、第一項は、2文字目の文字そのものですから、 'a'+"fun"-0x60 項を入れ替えて、 "fun"+'a'-0x60 'a'は、小文字のエーの文字コードですから、 "fun"+0x61-0x60 計算して、 "fun"+1 ここまでで、もとのコードは、次のようになります。 main() { printf("%six\n\0","fun"+1);} printfの第一引数が%sで始まっているので、第二引数は、文字列へのポインタが期待されていることになります。 それに従って、"fun"+1を解釈すると、文字列リテラルは、文字配列へのポインタと等価ですから、ポインタに1を足して、そのポインタを渡しているとすると、"un"を渡していることになります。 main() { printf("%six\n\0","un");} はい。これで、終着です。 このプログラムの実行結果は? 原記事に書いてあるとおりですね。 だれよ。こんなの考えるの=^・・;= 久しぶりに、Cの解読やったわ。まぁ、お遊び企画の例題だからこれで良いわけですけど。いかにコーティング規約が重要かを再認識されてくれます=^・。・^=
その他の回答 (2)
- notnot
- ベストアンサー率47% (4900/10358)
どの辺でつまづいているのでしょう? #define unix 1 なので、 main() { printf(&1["\021%six\n\0"],(1)["have"]+"fun"-0x60);} 説明にあるとおり、x[y] と y[x] は同じなので、 main() { printf(&("\021%six\n\0"[1]),"have"[1]+"fun"-0x60);} インデクス1の場所の文字とそのアドレスなので、 main() { printf("%six\n\0",'a'+"fun"-0x60);} 'a' は 0x61なので、 main() { printf("%six\n\0","fun"+1);} 無駄な部分を省くと、 main() { printf("%six\n","un");}
お礼
回答ありがとうございます。 つまづいていると言うよりも、C言語の細かい仕様をきちんと把握してないためになんとなくでしか理解できてなかったので詳しい解説が欲しいと思い質問させて頂きました。
- Tacosan
- ベストアンサー率23% (3656/15482)
まさにそのページに書いてあるわけですが, どこが分からないんでしょうか?
補足
確かに書いてあることで納得することはできるのです。 言い換えると、どのようなテクニックでどのように動かしているのかです。 &unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60 の部分が意味不明です。
お礼
上から読み進めていったところ納得できました。 こんなにいろいろな捻りを加えて書かれていたのですね。 改めてコーディングについてきちんと考えなおさないといけないという指標になりました。 とても細かく回答していただきありがとうございました。