←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.3696

関数ポインタについてです。
投稿者---つよし(2005/05/01 15:53:46)


お疲れ様です。Cの初心者です。
環境は、WINXPでVisual Stdio6.0++です。

下記の簡単な関数ポインタを使用したプログラムで、
実行結果には、満足しているのですが

デバッグをして、
pf = PRINT;
の行で、pfに格納されているアドレスを確認したところ
別のアドレスが格納されていました。

アセンブラ言語で見ると、一度、PRINT関数のアドレスを
ポインタで格納しているっぽい感じがするのですが(推測)
よくわかりません。

申し訳ないのですが、ご教授お願いいたします。
それでは失礼します。

#include <stdio.h>

void PRINT(void)
{
  printf("鈴木一郎\n");

}

void main(void)
{
    void (*pf)(); /* 関数ポインタ */

    pf = PRINT;
    pf();        

}



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数ポインタについてです。 3697 まきじ 2005/05/01 16:24:56


No.3697

Re:関数ポインタについてです。
投稿者---まきじ(2005/05/01 16:24:56)


>デバッグをして、
>pf = PRINT;
>の行で、pfに格納されているアドレスを確認したところ

どう確認したのでしょうか?

>別のアドレスが格納されていました。

別のアドレスとは?
期待したアドレスでなかったってことでしょうか?

>アセンブラ言語で見ると、一度、PRINT関数のアドレスを
>ポインタで格納しているっぽい感じがするのですが(推測)
>よくわかりません。

変数へのポインタと同じ概念だと思います。


この投稿にコメントする

削除パスワード

No.3698

Re:関数ポインタについてです。
投稿者---つよし(2005/05/01 17:30:01)


お返事、ありがとうございます。

>どう確認したのでしょうか?

デバック機能で、確認しました。
ウォッチ機能がありますよね。
それで確認しました。

>別のアドレスとは?
>期待したアドレスでなかったってことでしょうか?

はい、自分の環境では、PRINT関数は、0x00402010を指しています。
ですが、
pf = PRINT;
行後に、pfは、0x00402010が格納されていません。


>変数へのポインタと同じ概念だと思います。
すいません。よくわかりません。
なぜ、上記のようなことをするのですか?
pfには、0x00402010を代入すればいいのではないのでしょうか?


すいません、よろしくお願いします。




この投稿にコメントする

削除パスワード

No.3699

Re:関数ポインタについてです。
投稿者---まきじ(2005/05/01 17:41:04)


>はい、自分の環境では、PRINT関数は、0x00402010を指しています。
>ですが、
>pf = PRINT;
>行後に、pfは、0x00402010が格納されていません。

prinf("%p",pf);
とすれば、「00401000」の様な値が表示されると思います。

prinf("%d",pf);
とすれば、デバッグ機能の方で確認した、似た値になると思います。

>pfには、0x00402010を代入すればいいのではないのでしょうか?

定義した関数が、メモリ上のどこに格納されるかは分かりません。
実行する度に、格納先(アドレス)は異なります。



この投稿にコメントする

削除パスワード

No.3700

Re:関数ポインタについてです。
投稿者---とおり(2005/05/02 00:45:34)


>はい、自分の環境では、PRINT関数は、0x00402010を指しています。
>ですが、
>pf = PRINT;
>行後に、pfは、0x00402010が格納されていません。

今回のWindows/x86/VC環境であれば、おそらくまきじさんの仰るとおり
になると思いますが、一応、実装依存の話です。

関数ポインタを使っての関数callがどのように行われるかは、実装依存
であり、実際の関数の先頭アドレスを保持する、数wordsの関数descriptor
といった構造を介して、関数ポインタcallが実装される場合もあります。
(Unix系のいくつかの環境では、そうだったはず…)


この投稿にコメントする

削除パスワード

No.3701

Re:関数ポインタについてです。
投稿者---つよし(2005/05/02 12:11:25)


おつかれさまです。
まきじさん、とおりさんお返事ありがとうございました。

>関数ポインタを使っての関数callがどのように行われるかは、実装依存
>であり、実際の関数の先頭アドレスを保持する、数wordsの関数
>descriptorといった構造を介して、関数ポインタcallが実装される場合>もあります。(Unix系のいくつかの環境では、そうだったはず…)

ですが、今度は、staticを付けたとき、 pf = PRINT;
行後には、期待したアドレスが代入されていました。

関数の先頭を保持してないんです。
実装依存ですかぁ〜。少し勉強します。

ありがとうございました。
失礼します。

#include <stdio.h>

static void PRINT(void)
{
  printf("勝尾昌弘\n");
}

void main(void)
{
    static void (*pf)();

    pf = PRINT;
    pf();         

}




この投稿にコメントする

削除パスワード

No.3703

Re:関数ポインタについてです。
投稿者---とおり(2005/05/02 15:40:59)


>ですが、今度は、staticを付けたとき、 pf = PRINT;
>行後には、期待したアドレスが代入されていました。

試していないし、実装依存の話なので、あくまで推測の範囲ですが、
(MSのVC開発者にでも聞かない限り、推測の範囲を出ませんが…)
staticをつけた関数は、そのコンパイル単位でしか使用できない関数となります。
これは、内部リンケージと呼ばれるリンク(関数の解決)になり、このファイルを
コンパイルする時点で呼び先関数の解決が可能で、関数の先頭アドレスがそのまま
使われるのでしょう。

一方、staticでない関数というのは、他のコンパイル単位からも使用できるので
外部リンケージとなります。
今回問題となったのは、この外部リンケージの実装方法がどうなっているのか
ということです。
で、いろいろ周辺アドレスを調べれば、実装を推測できるとは思いますが、
詳細な仕様となるとやはりMSに聞かないとわからない気がします。

まあ、仮に詳細な仕様が確認できたとしても、こんな仕様はいつ変更されても
文句の言えない内部仕様的な部分なので、当然ですが、この仕様に依存した
プログラムを書くべきではありません。(今回はただの実験でしょうけど)


この投稿にコメントする

削除パスワード

No.3709

Re:関数ポインタについてです。
投稿者---nop(2005/05/02 23:05:40)


>はい、自分の環境では、PRINT関数は、0x00402010 を指しています。
>ですが、

 PRINT関数が0x00402010から始まっている

と言う事は、どの様にして確認したのですか?


この投稿にコメントする

削除パスワード

No.3710

Re:関数ポインタについてです。
投稿者---つよし(2005/05/03 01:18:52)


お疲れさまです。

>PRINT関数が0x00402010から始まっている
>と言う事は、どの様にして確認したのですか?


はい、デバック機能で、まずウォッチで確認し、
その後、混合モード(アセンブラ言語)で確認しました。







この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity