2011-07-12 12 views
1

このコードを検討:#1の問題はM()を展開した後、結果はN_を含み、前がXと一緒に連結し、プリプロセッサはそれを検出し、展開することであるマクロ展開を遅らせる

#define N_ 0 
#define N_X 1 
#define M(a) N_ 

M(arg)X; // #1 -- I'd like this to expand to N_X, and ultimately 1; but it's 0X instead 
M(arg);  // #2 -- this should and does expand to 0 

を。 プリプロセッサーがN_Xの代わりにN_Xを見つけるように、何らかの形でこのマクロの結果の再スキャンを遅らせることができますか?

答えて

7

まず、N_ XN_Xの間に異なるがあります。最初は2つのトークンです。 1つのトークンを形成するには、トークン貼り付け演算子##を使用する必要がありますが、この演算子は、マクロ展開を阻害するので、この:そのはM(a)なくN_をペーストしようとしているので、

M(a) ## X //Compiler error can't paste ')' and X 

は、コンパイルエラーが発生します。

#define PRIMITIVE_CAT(x, y) x ## y 
#define CAT(x, y) PRIMITIVE_CAT(x, y) 

しかし、あなたのケースで、これはまだ動作しません:

CAT(M(a), X) //expands to 0 
マクロはマクロの余分なレベルを使用して貼り付ける前に展開するためにあなたは(これは本当に一般的に使用されるマクロ)を許可することができます

これは、関数マクロではなく、オブジェクトマクロを使用しているためです。あなたは機能マクロに変更した場合、それはあなたが望むどのように動作します:

#define N_() 0 
#define N_X() 1 
#define M(a) N_ 

CAT(M(arg), X)() // expands to 1 
M(arg)()  // expands to 0 

機能マクロは、より強力であり、あなたはそれらの拡大を遅らせることができます。ここでは、一回の走査のためにそれらを遅らせることができます方法は次のとおりです。このようなマクロ展開を遅らせる

#define EMPTY() 
#define DEFER(x) x EMPTY() 

N_() //Expands to 0 
DEFER(N_)() //Expands N_() 

は再帰がプリプロセッサで実現することができる方法の一つです。

2

いいえプリプロセッサは行単位で動作し、再帰やバックトラックを一切行いません。行を読み込み、特別な#行を処理するか、何かを置き換えて次の行に進みます。これはまた、#defineの前または#undefの後に置換を行わないことを意味します。この問題を回避する必要があります。

+0

とマクロは一般的に悪いです – Drakosha

+2

ドラコシャ:私は同意しません。それらとその落とし穴を学ぶと、彼らは便利なツールになることができます。 – orlp

+0

ナイトクラッカー:確かに、それらを学ぶ必要がありますが、実際にそれが最後のオプション(と私はあなたの答えをupvotedていない限り)を使用しないようにする必要があります – Drakosha

関連する問題