dポイントプレゼントキャンペーン実施中!

表題の件ですが、
プログラム読んでいて分からないことありましたので、
C言語の文法的なことですが、教えて下さいませ。
全然自信ないですが、自分の解釈も付けてみました…

質問(1)
#define MP_RELEASEWIN(p) MP_FreeWin((IWindow **)&(p))
中略
static void MP_FreeWin(IWindow ** ppif);
中略
static void MP_FreeWin(IWindow ** ppif)
{
中略
}

このような場合、最初の#defineは、
MP_RELEASEWIN(p)は、MP_FreeWin((IWindow **)&(p))だよ
と定義しているけど、前方宣言にはなっていないから
static voidでプロトタイプ宣言して、
最後に関数の定義を書いているって解釈で
合っているのでしょうか?

質問(2)
#define MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel) \
(pVtbl)->Enable = (pfnEn); \
(pVtbl)->Redraw = (pfnRd); \
(pVtbl)->HandleEvent = (pfnHE); \
(pVtbl)->Delete = (pfnDel)

これって、
MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel)

(pVtbl)->Enable = (pfnEn); \
(pVtbl)->Redraw = (pfnRd); \
(pVtbl)->HandleEvent = (pfnHE); \
(pVtbl)->Delete = (pfnDel)
の4行部分で置き換えているのでしょうか?
あと、(pfnDel)の最後だけ、「;」がないのは
約束事って理解でいいのでしょうか?

質問(3)
#define CMediaPlayer_CancelRedraw(p) { CALLBACK_Cancel(&(p)->m_cbRedraw); (p)->m_bRedraw = FALSE; }

こんなのがあるのですが、
これは質問(2)と同じ意味なのでしょうか?
こっちにはカッコが付いているのですが、
これは、何か意味があるのでしょうか?

質問(4)
QINTERFACE(IWindow)
{
// Releases the window resources
void (*Delete)(IWindow * po);
};

この
void (*Delete)(IWindow * po);
の部分は、どういう風に理解すればいいのでしょうか?
カッコとか、*がついてますが…
Delete(IWindow * po);
とかいう関数に何かしているという意味なのでしょうか@@;
教えて下さい。

なんか、たくさん質問してますが、
よろしくお願い致しますm(__)m

A 回答 (6件)

質問(1)


#define指令(文ではない)は前処理で解決されますから、プロトタイプ云々の話は関係ありません。

質問(2)
あまりよい実装ではありませんが...

> の4行部分で置き換えているのでしょうか?

そうです。

> あと、(pfnDel)の最後だけ、「;」がないのは

MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel)の後に ; を付ける使い方を想定しているのでしょう。
私ならこんな実装ではなく、

#define MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel) \
  ((void)( \
  ((pVtbl)->Enable = (pfnEn)), \
  ((pVtbl)->Redraw = (pfnRd)), \
  ((pVtbl)->HandleEvent = (pfnHE)), \
  ((pVtbl)->Delete = (pfnDel)) \
  ))

のようにします。

質問(3)
> これは質問(2)と同じ意味なのでしょうか?

まあそうですね。

> こっちにはカッコが付いているのですが、
> これは、何か意味があるのでしょうか?

一貫性がないのはスキルが低いことの現われです。
こちらの方が先ほどより若干ましですが、式ではないのでやはり問題があります。

質問(4)
> void (*Delete)(IWindow * po);
> の部分は、どういう風に理解すればいいのでしょうか?

関数へのポインタです。

この回答への補足

回答ありがとうございます!
えーと、ちょっと質問させてください。
#define MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel) \
  ((void)( \
  ((pVtbl)->Enable = (pfnEn)), \
  ((pVtbl)->Redraw = (pfnRd)), \
  ((pVtbl)->HandleEvent = (pfnHE)), \
  ((pVtbl)->Delete = (pfnDel)) \
  ))
の部分ですが、
voidをカッコで囲んでいるのは
void型にキャストしているという意味で合っていますか?
大変レベルの低い質問ばかりで恐縮ですが
よろしくお願いいたします。

補足日時:2008/08/29 00:15
    • good
    • 0

>(1)


>static voidでプロトタイプ宣言して、
>最後に関数の定義を書いているって解釈で
違います。
#define MP_RELEASEWIN(p) MP_FreeWin((IWindow **)&(p)は
プリプロセッサの為、翻訳単位が異なります。
ソースコード内での
MP_RELEASEWIN(ほげほげ)
という記述に対して、
MP_FreeWin((IWindow **)&(ほげほげ);
に置き換える為の識別子です。

>(2)
>4行部分で置き換えているのでしょうか?
Yes。
行の終端に「\」がついているので、それがついていない
(pVtbl)->Delete = (pfnDel)の行までが1行とみなされ
#defineでの置換対象になります。

>あと、(pfnDel)の最後だけ、「;」がないのは
>約束事って理解でいいのでしょうか?
別に約束事では有りませんが、
MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel);
という使い方を意識している為でしょう。
最後に「;」をつけると呼び出しは
MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel)
になってしまい、ここで終っているのかどうか分かりにくくなります。

>(3)
似たような意味ですが、ブロックが異なるので、
ifが2つ重なった場合など、ブロック演算子ありとなしで
動きが変わったりするので使い方に気をつけなければ行けません。

>(4)
QINTERFACEがどの様なものなのかによりますが見た目は、
「値を返さずIWindow型ポインタを引数に持つ関数へのポインタ変数」
Deleteを宣言しているように見えます。
    • good
    • 0
この回答へのお礼

aris-wizさんありがとうございます!
jactaさんのと併せて読むと、
大変勉強になります!
MP_IWINDOW_SETVTBL(pVtbl, pfnEn, pfnRd, pfnHE, pfnDel);
の部分もすごく参考になりました!
みんなすごいな…しみじみ…

お礼日時:2008/08/29 18:55

void (*Delete)(IWindow * po);


これは関数ポインタです。
関数の名前も内部ではポインタとして扱われています。
下の例ではprint_addという関数とprint_subという関数を定義していますが
main関数ではfuncという関数ポインタを使って定義した関数を呼び出しています。
#include <stdio.h>

void print_add(int a, int b)
{
printf("%d\n", a+b);
}
void print_sub(int a, int b)
{
printf("%d\n", a-b);
}
int main(void)
{
void (*func)(int a, int b);
func = print_add;
func(1, 2); // print_add(1, 2)が呼ばれ3が表示
func = print_sub;
func(1, 2); // print_sub(1, 2)が呼ばれ-1が表示
return 0;
}
    • good
    • 0
この回答へのお礼

なるほど!!
関数の名前も、ポインターなんですね!
例題、すごくよく分かりました。
ありがとうございます。

お礼日時:2008/08/29 18:48

#2の者です。



仮に、
void Delete(IWindow * po);
と書くと、DeleteはIWindow *型の変数を受取って戻り値を返さない関数です。

しかし、関数名の頭に*を付けることで状況が一変します。
void *Delete(IWindow * po);
と書くことで、先に説明したとおりDeleteはポインターを返します。
そして、型が任意ですので、何型へのポインターにするかはDeleteを
呼び出す側の責任となります。例えば、
char *p;
p = Delete(IWindow * po);
としたり、
int *q;
q = Delete(IWindow * po);
としたり、といった具合です。
    • good
    • 0
この回答へのお礼

asuncionさん、何度もありがとうございます!
上手く言えないのですが、
分かったような気がします^^;
voidって、型が任意ってことなんですね!
戻り値を返さないっていう以外の意味があるんですね!
ふむむ、あってんのかな…
とにかく、C言語ってえらく難しいのですね><
コーヒー飲む回数が増えそうです…

お礼日時:2008/08/29 19:06

> voidをカッコで囲んでいるのは


> void型にキャストしているという意味で合っていますか?

はい。
こうしておかないと、間違った使い方を許してしまいます。
    • good
    • 0
この回答へのお礼

返事が遅れてしまいすいません。
了解しました!
ありがとうございます。

お礼日時:2008/08/29 18:46

少しだけフォロー。



>void (*Delete)(IWindow * po);
>の部分は、どういう風に理解すればいいのでしょうか?

Deleteは、IWindow *型の変数を受取って戻り値を返さない関数へのポインターです。

(*Delete) の前後のカッコを外して
void *Delete(IWindow * po);
と書くと、
Deleteは、IWindow *型の変数を受取って任意型へのポインターを返す関数
となり、意味が全く変わってしまいます。

この回答への補足

asuncion様、何か先ほどもお世話になった気が^^;
で、たぶん、すごくいいこと書いていただいたと思うので、
慎重に読んでみたのですが、
頭がだんだんオーバーヒートしてきて、
たった今、コーヒー淹れてきました!
ちょっとクールダウン…

>Deleteは、IWindow *型の変数を受取って
>任意型へのポインターを返す関数

えーと、ここが良く分かりません。
voidって戻り値がないよっていう意味では??
あ、もしや、
void *Delete(IWindow * po);
って、Delete(IWindow * po)はvoid型ですが、
*が付いているので、そのアドレスを入れるようになるから、
結局ポインター返しちゃうって理解でいいのでしょうか?
たびたびで恐縮ですが
よろしくご教授の程お願い致しますm(__)m

補足日時:2008/08/29 00:16
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!