C言語なら俺に聞け(入門編)Part 115 ID:SMi9Fbq0

3名無しさん@Next2ch:2015/03/18(水) 11:55:24.33 ID:SMi9Fbq0

Cプリプロセッサの#(文字列化)が期待通りに展開出来ない理由と対策

test1.c
#define STR(x) #x
STR(hoge)
を展開(cc -E test.c)すると
"hoge"
と期待通りに展開できるが、
test2.c
#define STR(x) #x
#define S hoge
STR(S)
と展開すると
"S"
と期待通りの展開はされない。これからその理由と対策について述べる。

規格書に準じてCプリプロセッサがどのように展開を行っていくか追跡してみよう。
(1)-(5)まではJISX3010の6.10.3から引用する。

(1)
関数形式マクロ名の次の前処理字句として(が現れたときには,マクロ名からこの(前
処理字句に対応する)前処理字句までの前処理字句列を,この定義内の置換要素並び
で置き換える(マクロ呼び出し)
-> STR(S)をその定義によって置き換える

(2)
最も外側の括弧によって囲まれた前処理字句の列は,関数形式マクロの実引数の並び
を形成する。
-> Sが実引数

4名無しさん@Next2ch:2015/03/18(水) 11:56:54.54 ID:SMi9Fbq0

続き

(3)
関数形式マクロの実引数を識別した後,実引数置換を行う。実引数の中に含まれるす
べてのマクロの展開後,置換要素並びの中の仮引数を対応する実引数で置き換える。
ただし,次の仮引数は除く
- #前処理字句又は##前処理字句が前にある仮引数
- ##前処理字句が後に続く仮引数
-> 実引数Sはマクロ展開されない

(4)
置換要素並びの中で,仮引数の直前に#前処理字句がある場合,対応する実引数の前
処理字句列のつづりを含んだ一つの単純文字列リテラル前処理字句によって,#前
処理字句と仮引数を置き換える。
-> "S"に展開される。

STR(S)を"hoge"に展開するにはどうすれば良いか?
#define STR(x) #x
#define STR(x) STR_(x)
#define S hoge
STR(S)
と二段階にすれば良い。

どのように展開されるか、追跡しよう。(2)までは同じだ。
-> 実引数Sがhogeに展開され、STR(S)はSTR_(hoge)に置き換えられる。

(5)
置換要素並び中のすべての仮引数を置き換え、更に#演算子及び##演算子の処理を
行った後,すべてのプレースマーカー前処理字句を削除する。その後,更に置き換
えるべきマクロ名があるかどうかを調べるために,ソースファイル上のその後のす
べての前処理字句と共にその結果の前処理字句を再走査する。
-> STR_(hoge)を再置き換えする (以下説明略)

5名無しさん@Next2ch:2015/03/18(水) 12:51:16.33 ID:SMi9Fbq0

>>4
訂正

(3)
関数形式マクロの実引数を識別した後,実引数置換を行う。実引数の中に含まれるす
べてのマクロの展開後,置換要素並びの中の仮引数を対応する実引数で置き換える。
ただし,次の仮引数は除く
- #前処理字句又は##前処理字句が前にある仮引数
- ##前処理字句が後に続く仮引数
-> 実引数Sはマクロ展開されない

(4)
置換要素並びの中で,仮引数の直前に#前処理字句がある場合,対応する実引数の前
処理字句列のつづりを含んだ一つの単純文字列リテラル前処理字句によって,#前
処理字句と仮引数を置き換える。
-> "S"に展開される。

STR(S)を"hoge"に展開するにはどうすれば良いか?
#define STR_(x) #x
#define STR(x) STR_(x)
#define S hoge
STR(S)
と二段階にすれば良い。

どのように展開されるか、追跡しよう。(2)までは同じだ。
(3)'
-> 実引数Sがhogeに展開され、STR(S)はSTR_(hoge)に置き換えられる。

(5)
置換要素並び中のすべての仮引数を置き換え、更に#演算子及び##演算子の処理を
行った後,すべてのプレースマーカー前処理字句を削除する。その後,更に置き換
えるべきマクロ名があるかどうかを調べるために,ソースファイル上のその後のす
べての前処理字句と共にその結果の前処理字句を再走査する。
-> STR_(hoge)を再置き換えする (以下説明略)


このIDをNGリストに追加する

今後このIDの書き込みやスレッドを表示したくない場合、以下のボタンをクリックしてください。
NGリストに追加

レスを書き込む