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

解決


My  2006-12-17 15:10:05  No: 63990

#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 20:41:26  No: 63991

#って何の演算子?


超初心者  2006-12-17 22:25:16  No: 63992

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


michi  2006-12-17 22:30:27  No: 63993

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

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


Ban  2006-12-18 01:47:01  No: 63994

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


My  2006-12-18 02:52:50  No: 63995

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

>超初心者様
>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-18 02:59:58  No: 63996

#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-18 03:16:14  No: 63997

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

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


michi  2006-12-18 03:44:53  No: 63998

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

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

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


dairygoods  2006-12-18 19:18:07  No: 63999

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

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

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

>#define TOSTR2(n) #n

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

> #define TOSTR(n) TOSTR2(n)

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


My  2006-12-19 10:31:35  No: 64000

>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-20 03:38:34  No: 64001

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


My  2006-12-20 11:16:51  No: 64002

>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 12:18:07  No: 64003

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


My  2006-12-20 12:24:59  No: 64004

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


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加