可変個のマクロの作成方法(引数の変数の数)


196

特定の数ではなく、任意の数のパラメーターを受け入れるマクロをCで記述したい

例:

#define macro( X )  something_complicated( whatever( X ) )

どこX任意の数のパラメータであります

whateverオーバーロードされており、2つまたは4つのパラメーターで呼び出すことができるため、これが必要です。

マクロを2回定義しようとしましたが、2番目の定義が最初の定義を上書きしました。

私が使用しているコンパイラはg ++(より具体的には、mingw)です。


8
CまたはC ++が必要ですか?Cを使用している場合、なぜC ++コンパイラでコンパイルするのですか?C ++には標準の可変長マクロがないため、適切なC99可変長マクロを使用するには、C ++コンパイラーではなく、C99(gccなど)をサポートするCコンパイラーでコンパイルする必要があります。
Chris Lutz、

まあ、私はC ++がこの点でCのスーパーセットであると想定しました..
09年

tigcc.ticalc.org/doc/cpp.html#SEC13には、可変個のマクロの詳細な説明があります。
Gnubie


3
将来の読者のために:CはC ++の派生物ではありません。それらは多くの多くのものを共有しますが、それらが互いのサブセットおよびスーパーセットになることを阻止するルールがあります。
Pharap 2017

回答:


295

C99の方法で、VC ++コンパイラでもサポートされています。

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)

8
C99ではVA_ARGSの前に##が必要だとは思いません。それは単にVC ++かもしれません。
Chris Lutz、

97
VA_ARGSの前の##の理由は、変数引数リストが空の場合に、先行するコンマを飲み込むためです。FOO( "a")はprintf( "a")に展開されます。これはgcc(および多分vc ++)の拡張です。C99では省略記号の代わりに少なくとも1つの引数が必要です。
jpalecek 2009年

108
##必要ではなく、移植性もありません。#define FOO(...) printf(__VA_ARGS__)ポータブルな方法で仕事をします。fmtパラメータは定義から省略することができます。
alecov

4
IIRC、##はGCC固有であり、ゼロのパラメーターを渡すことができます
Mawgはモニカを

10
##-syntaxは、llvm / clangおよびVisual Studioコンパイラーでも動作します。したがって、移植性はないかもしれませんが、主要なコンパイラによってサポートされています。
K.ビアマン2014

37

__VA_ARGS__それを行うための標準的な方法です。必要がない場合は、コンパイラ固有のハックを使用しないでください。

元の投稿にコメントできないのは本当にイライラします。いずれにせよ、C ++はCのスーパーセットではありません。C++コンパイラを使用してCコードをコンパイルするのは、ばかげています。ドニーはしないことをしないでください。


8
「C ++コンパイラでCコードをコンパイルするのは本当にばかげています」 =>誰もが(私を含めて)考えていない。:インスタンスC ++コアのガイドラインを参照してください CPL.1:CにC ++を好むCPL.2:あなたは、Cを使用するCおよびC ++の共通のサブセットを使用し、C ++とCのコードをコンパイルする必要がある場合。私は互換性のあるサブセットでプログラミングする価値がないようにするために本当に必要な「Cのみのイズム」を考えるのは大変であり、CおよびC ++の委員会は互換性のあるサブセットを利用できるようにするために懸命に取り組んできました。
HostileForkはSEを信頼してはいけないと言っています2016

4
@HostileFork十分に公平ですが、もちろん C ++の人々はC ++の使用を奨励したいと考えています。しかし、他の人は同意しません。たとえば、Linux Torvaldsは、C ++コンパイラでのコンパイルを許可するために識別子classklassに置き換えようとする複数の提案されたLinuxカーネルパッチを明らかに拒否しました。また、あなたをつまずくいくつかの違いがあることに注意してください。たとえば、3項演算子は両方の言語で同じように評価されず、inlineキーワードはまったく異なるものを意味します(別の質問から学んだように)。
カイルストランド

3
オペレーティングシステムのような本当にクロスプラットフォームのシステムプロジェクトの場合、Cコンパイラがより一般的であるため、厳密なCに忠実に従う必要があります。組み込みシステムでは、C ++コンパイラのないプラットフォームがまだあります。(通過可能なCコンパイラのみを備えたプラットフォームがあります!)C ++コンパイラは、特にサイバーフィジカルシステムに対して、私を緊張させます。
ダウンビート

2
@downbeatプロダクションにC ++を使用するかどうかに関係なく、心配する必要がある場合は、C ++でコンパイルできることで、静的分析の魔法の力が得られます。Cコードベースで作成したいクエリがある場合、特定のタイプが特定の方法で使用されているかどうか疑問に思っている場合は、type_traitsの使用方法を学ぶことで、そのターゲットツールを構築できます。Cの静的解析ツールに
多額の費用を払うには

1
Linuxの問題について話している。( "Linux Torvalds" haと書かれていることに気づきました!)
2018

28

私はそれが可能だとは思わない、あなたが二重の括弧でそれを偽造することができる...あなたが個別に引数を必要としない限り、

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))

21
可変個のマクロを使用することは可能ですが、二重括弧を使用することをお勧めします。
デビッドロドリゲス-ドリベス2009年

2
マイクロチップ社のXCコンパイラは可変長マクロをサポートしていないため、この二重括弧のトリックが最善の方法です。
gbmhunter 2016

10
#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

コンパイラーが可変個のマクロを理解しない場合は、次のいずれかを使用してPRINTを取り除くこともできます。

#define PRINT //

または

#define PRINT if(0)print

最初はPRINT命令をコメント化し、2番目はNULL if条件のためにPRINT命令を防ぎます。最適化が設定されている場合、コンパイラーは次のような実行されない命令を削除する必要があります。if(0)print( "hello world"); または((void)0);


8
#define PRINT // PRINTは//に置き換えられません//
bitc

8
#define PRINT if(0)printは、呼び出しコードがPRINTを呼び出すための独自のelse-ifを持っている可能性があるため、良い考えではありません。#define PRINT if(true); else print
bitc

3
標準的な「何もせず、優雅に」は{} while(0)を実行することです
フォンブランド

ifコード構造を考慮した「これを行わない」の適切なバージョンはif (0) { your_code } else、マクロ展開後のセミコロンがを終了することelseです。whileバージョンは次のようになります。バージョンwhile(0) { your_code } の問題do..whileは、コードdo { your_code } while (0)が1回実行され、保証されていることです。3つのケースすべてで、your_codeが空の場合、それは適切do nothing gracefullyです。
Jesse Chisholm、2015

4

ここではg ++について説明しますが、これはC99の一部であるため、誰にとっても機能するはずです。

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

簡単な例:

#define debug(format, args...) fprintf (stderr, format, args)

3
GCCの可変個のマクロはC99可変個のマクロではありません。GCCに C99可変マクロがありますが、C99はC ++の一部ではないため、G ++はそれらをサポートしていません。
Chris Lutz、

1
実際、g ++はC99マクロをC ++ファイルにコンパイルします。ただし、「-pedantic」を指定してコンパイルした場合は警告が表示されます。
Alex B

2
C99ではありません。C99はVA_ARGSマクロを使用します)。
qrdl 2009年

1
C ++ 11もをサポート__VA_ARGS__していますが、以前のバージョンのコンパイラでも拡張機能としてサポートされています。
Ethouris 16

1
これは、printf( "hi")では機能しません。var argsがない場合。これを修正する一般的な方法はありますか?
BTRナイドゥ2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.