#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
STR3 == "s1"を連結することは可能ですか?これを行うには、引数を別のマクロ関数に渡します。しかし、直接的な方法はありますか?
両方とも文字列の場合は、次のようにします。
#define STR3 STR1 STR2
プリプロセッサは、隣接する文字列を自動的に連結します。
編集:
以下に示すように、連結を行うのはプリプロセッサではなくコンパイラです。
文字列リテラルは言語レベルで連結されるため、この種のソリューションは必要ありません。「s」「1」は有効なプリプロセッサトークンではないため、とにかく機能しません。
[編集:残念ながらいくつかの賛成票を受け取った以下の誤った「Just for the record」コメントに応答して、上記のステートメントを繰り返し、プログラムの断片を観察します
#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")
gccの前処理フェーズからこのエラーメッセージを生成します。error: "" s ""および "" 1 ""を貼り付けると、有効な前処理トークンが得られません
]
ただし、一般的なトークンの貼り付けには、これを試してください:
/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B
/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)
次に、たとえば、s
がマクロとして定義されている場合を除き、PPCAT_NX(s, 1)
とPPCAT(s, 1)
の両方が識別子s1
を生成します。その場合、PPCAT(s, 1)
は<macro value of s>1
を生成します。
テーマに続くのは、これらのマクロです。
/*
* Turn A into a string literal without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define STRINGIZE_NX(A) #A
/*
* Turn A into a string literal after macro-expanding it.
*/
#define STRINGIZE(A) STRINGIZE_NX(A)
次に、
#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"
対照的に、
STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"
#define T1T2 visit the Zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the Zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
ヒント:上記のSTRINGIZE
マクロはクールですが、間違えたときに引数がマクロではない場合、名前にタイプミスがあるか、ヘッダーファイル#include
を忘れてしまった場合-コンパイラは、エラーなしで、意図したマクロ名を文字列に喜んで入れます。
STRINGIZE
への引数が常に通常のC値を持つマクロである場合、
#define STRINGIZE(A) ((A),STRINGIZE_NX(A))
一度展開して有効性を確認し、それを破棄してから、再び文字列に展開します。
"ENOENT"
の代わりにSTRINGIZE(ENOENT)
が"2"
になってしまった理由を理解するのにしばらく時間がかかりました... errno.h
を含めていませんでした。