関数マクロの引数にマクロを使うには?

解決


My  2006-12-17 06:10:05  No: 63990  IP: 192.*.*.*

#define A hoge
#define B piyo

マクロで書かれた2つの文字A,Bを結合してprintfで表示したいのですが、
次のように関数マクロの引き数に関数マクロをつかっても、マクロが変換されないで
そのままになってしまいます。

#define STRCAT(a,b) a ## b
#define TOSTR(n) #n

int  main(int argc,char* argv[]){
      printf(TOSTR(STRCAT(hoge,piyo)));
}

実行結果。
C:\>STRCAT(hoge,piyo)

もしかして関数マクロの中にマクロはだめなのでしょうか?
ご存知のかたがいらっしゃいましたらどうかよろしくお願いします。

編集 削除
馬場  2006-12-17 11:41:26  No: 63991  IP: 192.*.*.*

#って何の演算子?

編集 削除
超初心者  2006-12-17 13:25:16  No: 63992  IP: 192.*.*.*

TOSTRが先に実行されてしまうってことか。

編集 削除
michi  2006-12-17 13:30:27  No: 63993  IP: 192.*.*.*

このようにするとどうなりますか?

#define STRCAT(a,b) a ## b
#define TOSTR2(n) #n
#define TOSTR(n) TOSTR2(n)

編集 削除
Ban  2006-12-17 16:47:01  No: 63994  IP: 192.*.*.*

> #って何の演算子?
プリプロセッサの引数で、値ではなく引数の文字列を取るためのものです。
ちなみに、## ってのは、文字連結用。

編集 削除
My  2006-12-17 17:52:50  No: 63995  IP: 192.*.*.*

>みな様
お返事ありがとうございます。

>超初心者様
>TOSTRが先に実行されてしまうってことか。
そうみたいなんです。

>michi様
いわれたとおり実行してみました。

#define STRCAT(a,b) a ## b
#define TOSTR2(n) #n
#define TOSTR(n) TOSTR2(n)

int  main(int argc,char* argv[]){
      printf(TOSTR(STRCAT(hoge,piyo)));
}

実行結果。
C:\>hogepiyo
なんでこれでうまくいくの??????

編集 削除
My  2006-12-17 17:59:58  No: 63996  IP: 192.*.*.*

#define A hoge
#define B piyo
#define STRCAT2(a,b) a ## b
#define STRCAT(a,b) STRCAT2(a,b)
#define TOSTR2(n) #n
#define TOSTR(n) TOSTR2(n)

int  main(int argc,char* argv[]){
      printf(TOSTR(STRCAT(A,B)));
}

実行結果。
C:\>hogepiyo

上記のようにすることで目的のマクロができました。
でも、どうしてこれでうまくいくのかわかりません。
たまたまコンパイラがこうゆう仕様だからでしょうか?
鼻から悪魔なことになってないでしょうか?

編集 削除
My  2006-12-17 18:16:14  No: 63997  IP: 192.*.*.*

すみません書きわすれましたがコンパイラはMINGW-JP(MIGWの日本語版)のgccです。

(あとmain関数の最後にreturn;を書くのもわすれてました。)

編集 削除
michi  2006-12-17 18:44:53  No: 63998  IP: 192.*.*.*

完全に処理系依存で、私も詳しく分かりません。

とりあえず、
TOSTR(STRCAT(hoge,piyo)) -> "STRCAT(hoge,piyo)"
の変換をさけるために、余計にマクロ(TOSTR2,STRCAT2)を挟んであげればいいようですね。

ちなみに私は
TOSTR(__LINE__) -> "__LINE__"
にならないようTOSTR2を使ってます。

編集 削除
dairygoods  2006-12-18 10:18:07  No: 63999  IP: 192.*.*.*

> 上記のようにすることで目的のマクロができました。
> でも、どうしてこれでうまくいくのかわかりません。
> たまたまコンパイラがこうゆう仕様だからでしょうか?

標準仕様どおりでよいと思います。

JIS X 3010 6.10.3.1 実引数置換
| 実引数の中に含まれるすべてのマクロの展開後、置換要素並びの中の
| 仮引数を対応する実引数で置き換える。ただし、次の仮引数は除く。
| - #前処理字句又は##前処理字句が前にある仮引数
| - ##前処理字句が後に続く仮引数


>#define TOSTR2(n) #n

これは #n という使われ方をしているので、
実引数のマクロ展開は行われない。

> #define TOSTR(n) TOSTR2(n)

これは n という使われ方をしているので、
実引数のマクロ展開が行われる。

編集 削除
My  2006-12-19 01:31:35  No: 64000  IP: 192.*.*.*

>michi 様、dairygoods様
レス大変ありがとうございます。

>実引数の中に含まれるすべてのマクロの展開後、置換要素並びの中の
>仮引数を対応する実引数で置き換える。

#define TOSTR(n) TOSTR2(n)
とはまずnをマクロ展開後、TOSTR2()の関数マクロが実行されるということ??

ということは・・・・・・・・・
TOSTR(STRCAT(A,B))
はまず実引数?のSTRCAT(A,B)がマクロ展開されるんだけど、さらにその実引数のA,Bが最初にマクロ展開されて、
TOSTR(STRCAT(hoge,piyo))になり、
TOSTR(STRCAT2(hoge,piyo))になり、
TOSTR(hogepiyo)になって
TOSTR2(hogepiyo)
最後に"hogepiyo"となるんですね!!!!
・・・あってますでしょうか?

編集 削除
jackdaw  2006-12-19 18:38:34  No: 64001  IP: 192.*.*.*

単純に、
#define STRCAT(a,b) #a #b
だけでもいいとおもうのですが…

編集 削除
My  2006-12-20 02:16:51  No: 64002  IP: 192.*.*.*

>jackdaw様
レスありがとうござます。下記のコードを実行してみました。

#define A hoge
#define B piyo
#define STRCAT(a,b) #a #b

int main(int argc,char* argv[]){
   printf(STRCAT(A,B));
   return 0;
}

実行結果は"AB"となり目的の機能をはたしてくれません。
#define STRCAT2(a,b) #a #b
#define STRCAT(a,b) STRCAT2(a,b)
とすれば実行結果は"hogepiyo"になりました。

ただどうして#a#bの間のスペースはなくなるんでしょうか?

編集 削除
My  2006-12-20 03:18:07  No: 64003  IP: 192.*.*.*

>ただどうして#a#bの間のスペースはなくなるんでしょうか?
検索したらでてきました。
C 言語では、並んだ二つの文字列定数は一つの文字列定数に併合する決まりになっているんですね。ありがとうございました。

編集 削除
My  2006-12-20 03:24:59  No: 64004  IP: 192.*.*.*

>みな様
"解決"です。
レス本当にありがとうございました。勉強になりました。

編集 削除