我知道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/