3

C Preprocessor、Macro "Overloading"VA_NARGSで説明されているように、しばらく前からマクロを認識していましたが 、それを機能させるために必要な大量のボイラープレートにいつも気が進まなかったのです。

最近、この機能が必要になったので、歯を食いしばって、必要なすべてのマクロ コードをすべて「栄光」の形で書きました。

私の特定のケースでは、すべての varargs 引数が特定の型であることを一貫して信頼できます。sizeofこれにより、おそらく配列型を使用するより良い方法があるのではないかと思いました。ローカル システムでこれを試してみましたが、うまくいくようです。ただし、このソリューションは脆弱である可能性があることを懸念しています(型の制限を超えています)。

私の質問は次のとおりです。これは実際、問題に対する安全で合理的​​な解決策ですか? または、おそらく: これを使用すると、結局、どのようなトラブルが発生するのでしょうか? そして最後に: 試行 (下記) に問題がある場合、一般的なアプローチを救うために適用できる微調整はありますか?

コードとデモmain()関数を次に示します。この場合、varargs 引数はすべて int でなければなりません:

#include <stdio.h>

#define ARG_ARRAY(...) ((int[]) { __VA_ARGS__ })
#define ARG_COUNT(...) (sizeof (ARG_ARRAY(__VA_ARGS__)) / sizeof (int))

#define STUFF(label, ...) \
    stuff(label, ARG_COUNT(__VA_ARGS__), ARG_ARRAY(__VA_ARGS__))

void stuff(char *label, int count, int *values) {
    printf("[%s] count %d", label, count);

    for (int i = 0; i < count; i++) {
        printf("%s %d", (i == 0) ? ":" : ",", values[i]);
    }

    printf("\n");
}

int return1(void) {
    printf("Called `return1()`.\n");
    return 1;
}

int main(int argc, char **argv) {
    STUFF("blort");
    STUFF("frotz", return1());
    STUFF("fizmo", 2 + 3, 6 + 1);
    STUFF("glorf", 99, 999, 999);
    STUFF("igram", 9, 8, 7, 6, 5, 4, 3, 2, 1);
}

ここにトランスクリプトがあります:

[blort] count 0
Called `return1()`.
[frotz] count 1: 1
[fizmo] count 2: 5, 7
[glorf] count 3: 99, 999, 999
[igram] count 9: 9, 8, 7, 6, 5, 4, 3, 2, 1

出力はreturn1()、関数が 2 回呼び出されていないことを確認するためのものです。


更新:

(int[]) { args }C99 であるが C++ ではないことがコメントで指摘されました。私の場合、問題のコードに C コンパイラを使用することは期待できますが、それでもこの特定の制限を知っておくとよいでしょう。

削除された回答で、C99 では varargs マクロ引数を少なくとも 1 つの実引数で埋める必要があることが指摘されました (ただし、仕様はその点でせいぜいあいまいだと思います)。私が手元に持っているコンパイラ (OS X の Clang) は、コードを受け入れますが、@ 2501 がコメントで適切に示しているように、-Wall実際には に文句を言います。-pedantic

-pedanticサイズがゼロの配列(引数なしの展開(int[]) { })についても文句を言いますが、これは常にダミー要素を含めることで修正できます。

4

1 に答える 1