No.4ベストアンサー
- 回答日時:
Jizouと申します。
順に考えていきます。
main(){ printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
(ヒント:#define unix 1)
== Step 1: =========================================================
#defineマクロはソースコードのコンパイルが行われる前に実行されます
から、ソースコード内の unix という文字列はすべて 1 という文字に
置き換えられます。置き換えたものが次のソースです。
main(){ printf(&1["\021%six\012\0"],(1)["have"]+"fun"-0x60);}
== Step 2: =========================================================
次に "\021%six\012\0" を解釈します。
文字列中の \0nn という表現は nn を8進数として解釈しますので、\021 は
10進数で 17( = 8 * 2 + 1)、16進数で 11 を示す値となります。同じよ
うに \012 は 10進数で 10( = 8 * 1 + 2 )、16進数で 0a を示す値とな
ります。\0 は 0(ゼロ)です。
\021 == 17 == \0x11
\012 == 10 == \0x0a
ASCIIコード表で 17 が何を表すか分かりませんが、10 は「改行」を表しま
すので '\n' と同じ意味です。(改行と '\n' が厳密に同じかどうかはちょ
っと参考書をひっくり返さなければ分かりませんが、今回のケースでは同じ
と考えても問題ないと思います)
文字列の最後はもともと終端コードとして '\0' が1個入っていますので、
このソースの場合には '\0' コードが2個入ることになります。
結局 "\021%six\012\0" は "\0x11%six\n" と同じ意味になります。
main(){ printf(&1["\0x11%six\n"],(1)["have"]+"fun"-0x60);}
== Step 3: =========================================================
次が最も難解な部分だと思いますが、&1["\0x11%six\n"] を解釈します。
これは良く使う形としては answer_text[3] という形と同じです。
C言語では文字列変数を char answer_text[100]; のように定義すると
answer_text というラベルは宣言した文字列の先頭アドレスを表すラベルと
して扱われます。
この文字列の4文字目を取り出す場合に answer_text[3] という書き方をし
ますが、これは内部的には次のような形に変換される規則になっています。
answer_text[3] ===> *( answer_text + 3 )
answer_text というアドレスに 3 を加えて、そのアドレスから1文字取り
出すというわけです。
ところがこの変換式は answer_text の位置と 3 の位置に何を書いても上記
のように変換される規則になっています。ですので answer_text と 3 の位
置を入れ替えてもエラーなくコンパイルできてしまい、意味も同じになりま
す。
3[answer_text] ===> *( 3 + answer_text )
ですので 1["\0x11%six\n"] はカギ括弧の中と外を入れ替えた "\0x11%six\n"[1]
と同じ物なのです。この「文字列の後ろにインデックスを添える」という形
も普通は使いませんが、文字列変数も文字列も同じようなものだと思えばこ
れは「その文字列の2文字目を示す」ものだということがお分かりいただけ
ると思います。
1["\0x11%six\n"] ===> 文字列 "\0x11%six\n" の2文字目を示す。
今回のケースでは先頭にアンパサント(&)が付いていますので、さらに「そ
のアドレスを示す」ということになります。つまり
&1["\0x11%six\n"]
===> 文字列 "\0x11%six\n" の2文字目の先頭アドレスを示す。
===> "%six\n"
ということになります。(要するに先頭の1文字 '\0x11' を読み飛ばす)
main(){ printf( "%six\n", (1)["have"]+"fun"-0x60);}
== Step 4: =========================================================
お次は (1)["have"] です。
ここで (1) は 1 と同じですので実質的には 1["have"] と同じです。
これは上でやった内容と同じですので次のようになります。
(1)["have"] ===> 1["have"] ===> "have"[1]
これは「"have" の2文字目」という意味になりますので、'a' ということ
になります。
main(){ printf( "%six\n", 'a'+"fun"-0x60);}
== Step 5: =========================================================
その次は 'a'+"fun"-0x60 です。
文字 'a' は16進数では 61 ですので C言語の表記では \0x61 となります。
さてその次の "fun" ですが、ソースコード中の文字列は式の中では「その文
字列の先頭アドレス」を示す値となります。
したがってこの式は次のように解釈されます。
'a'+"fun"-0x60 ===> 0x61 + "fun" - 0x61 ===> "fun" + 1
文字列アドレスに1を加えるということは、2文字目のアドレスを示すとい
うことになります。
"fun" + 1 ===> "un"
したがって最初のソースコードは次のソースコードと同じ意味になります。
main(){ printf( "%six\n", "un" );}
== Step 6: =========================================================
ここで printf関数 の第1引数の中の "%s" は第2引数の文字列で置き換え
て出力されますので、最終的には次の文字列が表示されることになるわけで
す。
"unix"(+改行)
以上、お分かりいただけたでしょうか?
まだ分からない点などありましたら、コメントに書き込んで下さい。
Jizou
No.3
- 回答日時:
配列の解釈と文字とコードの変換が頭に浮かぶかどうかが問われているわけですね。
"abc"[1] → *("abc" + 1)
1["abc"] → *(1 + "abc")
このあたりの概念は馴染みずらい所かもしれない。
No.2
- 回答日時:
unixは1を表すんですね。
知りませんでした。printf()が一つ呼ばれているだけですから、その引数の意味を示せばよいのだと思いますが、
まず、unix["\021%six\012\0"]ですが、アドレス1を先頭として、文字列"\021%six\012\0"の
アドレス分だけプラスした文字のアドレス・・・ということは、とりも直さず
文字列"\021%six\012\0"の2文字目のアドレスということになります。(先頭はゼロですから。)
で、\012は\nのことですから、この第一引数は"%six\n"と同じことになります。
第二引数は、同じ理屈で"have"の二文字目ですが、こちらはアドレスではありませんので、
'a'という値、つまり0x61になります。0x61に"fun"のアドレスを加え、0x61を引くということは
つまり"fun"の2文字目のアドレスと同じことですから、第二引数は"un"です。
つまり、このプログラムは
main(){printf"%six\n","un");}
ということです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセルでアルファベットか数...
-
文字列からタブコードを取り除...
-
【Excel VBA】複数ある特定の文...
-
EXCELで=より左の文字を一括で...
-
Excelで3E8を3.00E+8にしない方...
-
VBAでの Replace関数で、ワイル...
-
エクセルで文字列をtxtファイル...
-
エクセル 数値データを桁をそ...
-
Excelで指数表現しないようにす...
-
VBの「As String * 128」とは?
-
VBA2005 16進を2桁で表示したい。
-
アクセスで特定の数字以外(複...
-
エクセルで文字列の最大値を抽...
-
Msgboxの×が押されたとき
-
C#で年月を比較する
-
windows7のエクスプローラをVBA...
-
VBA テキストボックスの計算
-
CStringの文字列検索&抜き出し...
-
ORCLEでの小数の表示方法の変更...
-
VC++6.0 エディットボックス小...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルでアルファベットか数...
-
EXCELで=より左の文字を一括で...
-
文字列からタブコードを取り除...
-
VBAでの Replace関数で、ワイル...
-
Excelで指数表現しないようにす...
-
Excelで3E8を3.00E+8にしない方...
-
エクセルで文字列をtxtファイル...
-
【Excel VBA】複数ある特定の文...
-
Left関数とRight関数を合わせた...
-
同一セル内に関数と文字列を同...
-
アクセスで特定の数字以外(複...
-
MS SQLServer のSQLで文字列の...
-
エクセルで文字列の最大値を抽...
-
VBA2005 16進を2桁で表示したい。
-
ORCLEでの小数の表示方法の変更...
-
エクセル 数値データを桁をそ...
-
VBの「As String * 128」とは?
-
CStringの文字列検索&抜き出し...
-
エクセルでセル内の文字列の最...
-
Msgboxの×が押されたとき
おすすめ情報