我知道C Preprocessor, Macro "Overloading"中所述的VA_NARGS
有一阵子,但是我一直被让它工作所需的大量样板感到失望。

最近,我需要此功能,因此我不遗余力地编写了所有必需的宏代码,并写上了所有的“荣耀”。

在我的特定情况下,我可以始终依赖于所有varargs参数为特定类型。这使我认为使用sizeof和数组类型也许是更好的方法。我在本地系统上进行了尝试,它似乎可以工作。但是,我担心此解决方案可能很脆弱(超出类型限制)。

我的问题是:实际上,这是否是对该问题的安全且合理的解决方案?或者,也许是:如果我使用它,我到底要问什么麻烦?最后:在尝试存在问题的情况下(如下),是否可以进行一些调整以挽救一般方法?

这是代码,以及演示main()函数。在这种情况下,varargs参数都必须为整数:

#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()打印输出用于验证该函数未被两次调用。



更新:

注释中指出(int[]) { args }是C99,但不是C ++。就我而言,我可以指望对有关代码使用C编译器,但是了解此特定限制仍然很不错。

在现已删除的答案中指出,C99要求varargs宏参数至少由一个实际参数填充(尽管我认为规范在这方面充其量是模棱两可的)。我手边的编译器(在OS X上为Clang)接受-Wall的代码,但实际上对-pedantic抱怨,如@ 2501在其注释中恰当地说明了这一点。

-pedantic还抱怨数组大小为零(无参数扩展(int[]) { }),尽管可以通过始终包含一个虚拟元素来解决此问题。

最佳答案

如果宏参数都是有效且非无效的表达式,则可以尝试使用decltype,如下所示:

#include <tuple>
#define NARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value


不评估宏参数。例如:

#include <iostream>
#include <type_traits>

int main(int argc, char *argv[])
{
    std::cout << "Have "
              << NARGS("bar", 1, argc, 3, std::declval<int>())
              << " things\n";
}

关于c - 这个宏论点是否算计战术合法性?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26497854/

10-10 18:50
查看更多