##および__LINE__を使用したCマクロの作成(位置決めマクロを使用したトークンの連結)


107

行番号に基づいて名前を持つ関数を作成するCマクロを作成したいと思います。私は次のようなことができると思いました(実際の関数は中括弧内にステートメントがあります):

#define UNIQUE static void Unique_##__LINE__(void) {}

私は次のようなものに拡大することを望みました:

static void Unique_23(void) {}

それはうまくいきません。トークン連結では、位置決めマクロは文字通り処理され、最終的に次のように展開されます。

static void Unique___LINE__(void) {}

これは可能ですか?

(はい、これがどれほど役に立たないように見えても、私がこれを実行したい本当の理由があります)。


これを間接的なマクロ展開で機能させることができると思います。
ベンスティグリッツ

4
Cプリプロセッサで2回連結してマクロを展開する方法の重複の可能性"arg ## _ ## MACRO"?同じことが他に、任意のマクロのために行く__LINE__ことが一般的な使用例であるが(。
チロSantilli郝海东冠状病六四事件法轮功

回答:


176

問題は、マクロを置き換えるときに、文字列化演算子#もトークン貼り付け演算子##も適用されていない場合にのみ、プリプロセッサがマクロを再帰的に展開することです。そのため、間接参照の追加のレイヤーをいくつか使用する必要があります。再帰的に展開された引数でトークン貼り付け演算子を使用できます。

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

次に、の__LINE__展開中に行番号に展開さUNIQUEれます(#またはに関係しないため##)。その後、の展開中にトークンの貼り付けが行われTOKENPASTEます。

同じ行にマクロの__COUNTER__複数のインスタンスを作成する必要がある場合に備えて、評価されるたびに新しい整数に展開するマクロもあることに注意してくださいUNIQUE。注:__COUNTER__MS Visual Studio、GCC(V4.3以降)、およびClangでサポートされていますが、標準のCではありません。


3
GNU cppでは動作しません。TOKENPASTEは、LINEをリテラルとして使用します。TOKENPASTE(Unique_、LINE)は、Unique ___ LINE__
DDに

3
@DD:D'oh、今修正されました。それはない1、間接の2層を必要とする
アダムローゼンフィールド

__COUNTER__マクロはGCCで私のために動作しませんでした。が、__LINE__一つは、アドバタイズとして仕事をしました。
タイラー

2
msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspxによると、COUNTERを試す人のための追加情報です。これはMicrosoft固有のマクロです。
Elva

3
2レベルの間接参照が必要な理由の説明はありますか?#と##がない1つだけで試してみましたが、VS2017では拡張されません。どうやら同じことがGCCにも当てはまります。ただし、第2レベルの間接参照を追加すると、拡張されます。マジック?
Gabe Halsmer 2017年

-2

GCCは、結果を「文字列化」する必要がない限り、「ラッピング」(または実現)を必要としません。Gccには機能がありますが、ALLはプレーンなCバージョン1で実行できます(また、バークレー4.3 Cの方がはるかに高速で、使い方を学ぶ価値があると主張する人もいます)。

** Clang(llvm)は、マクロ展開のためにホワイトスペースを正しく行いません-空白を追加します(これは確かに結果をC識別子としての結果として破棄し、さらに前処理を行います)**、clangは単に#または*マクロ展開を行いませんCプリプロセッサとして数十年の間期待されています。主要な例はX11のコンパイルです。マクロ「Concat3」は壊れています。その結果はMISNAMED C Identifierになりましたが、もちろんビルドできません。そして、私はビルドの失敗が彼らの職業であることを始めています。

私はここでの答えは「標準を破る新しいCは悪いC」であると思います。これらのハックは常に(名前空間を破壊する)を選択しますが、理由もなくデフォルトを変更しますが、実際には「Cを改善」しません(独自の言い回しを除いて)。彼らがなぜ誰も彼らに責任を負わせていないすべての破損を免れる理由を説明するために作られた仕掛けが言います)。


以前のCプリプロセッサがUNIq _()__をサポートしなかったのは問題ではありません。これは、「コード内のコンパイラブランドのハッカーにハッカーのフラグを付ける」ことができ、標準に影響を与えずに機能する#pragmaをサポートしたためです。デフォルトは役に立たないワンタンの破損であり、同じ名前を使用しているときに関数が何をするかを変更するのと同じように(名前空間の破壊)マルウェアは私の意見です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.