• ベストアンサー

関数に値の代入 [C言語]

C言語初心者です。関数とポインタについて勉強していたのですが、ふと関数の型を知りたくなってVC++で型を調べてみたんです。そしたら、void型で引数のない関数の型は void (__cdecl*)() となっていました。voidと__cdeclはわかります。 そしてこれ型に*が入ってるじゃないですか。ということは関数はポインタということになると思います。なので私はもしかしたら値の代入ができるのではないか、と思ったのです。早速、 f1=f2;(f1とf2は型と内容の同じ関数) や、 (*f1)=(*f2); としてポインタの中身や参照先の関数の実態の値を処理中に書き換えてみようとしました。ですが、多分そうなるとは思ったのですが、コンパイルエラーが出ました。 《エラーの内容》 error C2106:'=':左のオペランドが、左辺値になっていません。 warning C4550:式は引数リストのない関数として評価します。 関数を書き換えようとすること自体馬鹿げていることは重々承知です。でも、微かにいけそうな気がするんですよ。代入させたくないなら関数の型は一律constにすると思うし(実際関数をconstをつけて宣言してもOKだった、(プロトタイプ有り無しでも))、関数への代入は問答無用で駄目なのならばそういうエラーメッセージを出すと思うんです。 関数の書き換えは100%無理でしょうか?それとも関数を書き換える方法があるでしょうか?回答よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

関数の型をどうやって調べたのか知りませんが... 例えば、 void foo(void); という関数の型は、void (void)型になります。そして、関数名を大多数の演算子のオペランドにする場合には、(配列名がそうであるのと同じように)関数へのポインタ型に暗黙的に型変換されます。この型がvoid (*)(void)です。 関数へのポインタ型のオブジェクト(変数)の宣言は、 void (*pf)(void); のように行います。このpfに対してであれば、 pf = &foo; あるいは pf = foo; のように代入することができます。 > 関数の書き換えは100%無理でしょうか?それとも関数を書き換える方法があるでしょうか? 普通は行いませんが、関数の書き換えは不可能ではありません。ただし、それはポインタの更新とはわけが違います。

noname#113783
質問者

お礼

関数の型はわざと型を調べたい変数にその型に変換できない型の変数を代入して、それをコンパイルして出てきたエラーメッセージから調べました。 >>関数の書き換えは不可能ではありません 関数の実装を書き換えることができました!char型のポインタに関数のアドレスを代入して、そのポインタ経由で値を代入するソースを書いてコンパイルしたら、ワーニングメッセージしか出ませんでした。ただ、適当な値を書き込んだので実行したら案の定プログラムが停止しました(汗)。もし、うまい位置に機械語の命令の値を代入したら「プログラムの処理中に関数を書き換える」みたいなトリッキーなプログラムも書けたりするのかな・・・? >>関数へのポインタ型に暗黙的に型変換されます。 配列と似ているんですね!違うところもありますが。 回答ありがとうございました!

その他の回答 (3)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.4

> うまい位置に機械語の命令の コードの実行が許されるような「うまい位置」にもご注意を。 #DEP、VirtualProtect

noname#113783
質問者

お礼

関数を書き換えるにはwindowsに色々と許可をとらないといけないんですか! 確かにWindowsが簡単に処理内容書き換えさせてくれるほどセキュリティゆるいってこともないかぁ。でもこうして見るとウイルスプログラムなんて簡単に作れちゃうんですね(作る気ないですけど!)。 回答ありがとうございました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

> もし、うまい位置に機械語の命令の値を代入したら「プログラムの処理中に関数を書き換える」みたいなトリッキーなプログラムも書けたりするのかな・・・? キャッシュの整合性を合わせることもお忘れなく。

noname#113783
質問者

お礼

データがキャッシュにも保存されていることがあるんですね。 初心者には難しい・・・1度コンピューターの仕組みの本を読んでみようかな。 回答ありがとうございました!

  • prophetok
  • ベストアンサー率44% (13/29)
回答No.1

関数ポインタで検索すればいろいろと参考になる情報あり。 ソートする際、コンパレータ(比較するための関数)の関数ポインタ、コールバック用関数のポインタを引数として利用するのは一般的です。 出てきたコンパイルエラーは char a[10]; char b[10]; char *p; a=b; //これはエラー p=a; //これはOK b=p; //これはエラー と同じで定数に対して値を代入しようといているのと一緒ではないですか。

noname#113783
質問者

お礼

関数ポインタならアドレスを変えられますね! >>定数に対して値を代入しようといているのと一緒ではないですか。 エラーの内容等を見た時に定数に値を代入した時と違うな、と感じました。 回答ありがとうございました!

関連するQ&A