我正在尝试调用一个采用可变参数的 C 函数,我需要将动态数量的参数传递给该函数。此外,这是一个我不付出很多努力就无法修改的 API,所以如果有任何可能使这项工作可行,我会接受它。
据我所知,va_list
不足以满足此目的,因为您不能传递 va_list
where ...
写在原始函数签名中。
其他问题的答案,例如 this one谈论如何将 ...
从一个函数传递到另一个函数,但这不是我正在做的。我需要实际动态生成参数列表,我没有将其作为 ...
获取。此外,我能找到的所有答案都依赖于能够修改函数以采用 va_list
,这在此处不是一个选项。
还有 this question ,尽管实际上并没有问同样的问题,但它被标记为上一个问题的骗局。同样,唯一的答案是建议将调用转换为使用 va_list
,这不是一个选项。
如果标准不包含执行此操作的方法,我会理解,但在这种情况下,我可以想象一个完全合理的实现。这与 alloca
没有太大区别。无论如何,如果不可能,那很好,但我希望 SO 社区意识到这不是 this question 的骗局。并且值得一个明确的答案。
我正在调用的 API 是用 C 编写的,但如果有一种方法可以用 C++ 执行此操作,我会考虑。
编辑:如果您有这些要求,它看起来像this answer using libffi是最好的方法。似乎没有办法在标准 C 或 GCC 扩展中执行此操作。
如果您使用 gcc 编译器,您可以使用 __builtin_va_arg_pack() 或 __builtin_apply(),参见 here .
例子:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
int my_printf(const char *fmt, ...)
{
void *args = __builtin_apply_args();
void *ret = __builtin_apply((void(*)())printf, args, 100);
__builtin_return(ret);
}
extern int my2_printf(const char *, ...);
extern inline __attribute__((__always_inline__,__gnu_inline__))
int my2_printf(const char *fmt, ...) {
return printf(fmt, __builtin_va_arg_pack());
}
int main()
{
my_printf("%s %s %s %s %s\n", "Hi", "I", "am", "kamil", "!");
my2_printf("%s %s %s %s\n", "Variadic", "args", "are", "fun");
return 0;
}
@编辑:
由于问题还涉及如何构建动态参数列表,然后将其传递给函数。您可以为每个需要支持的案例创建一个函数,并使用一个大开关来区分它们。
打印未知编译大小数组的示例:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <boost/preprocessor/repetition/repeat.hpp>
void print_array(size_t cnt, ...)
{
va_list va;
va_start(va, cnt);
printf("%s cnt=%d :", __func__, cnt);
for (size_t i = 0; i < cnt; ++i) {
printf(" %d", va_arg(va, int));
}
va_end(va);
printf("%s\n");
}
// we support an array up to that many arguments
#define CALL_PRINT_ARRAY_MAX 128
#define CALL_PRINT_ARRAY_ARGS(z, n, text) \
, arr[n]
#define CALL_PRINT_ARRAY_DECLARE(z, n, text) \
void call_print_array_##n (int arr[]) \
{ \
print_array(n BOOST_PP_REPEAT(n, CALL_PRINT_ARRAY_ARGS, ())); \
}
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_DECLARE, ())
#undef CALL_PRINT_ARRAY_DECLARE
#undef CALL_PRINT_ARRAY_ARGS
int call_print_array(int arr[], size_t n)
{
switch(n) {
#define CALL_PRINT_ARRAY_CASE(z, n, text) \
case n: call_print_array_##n(arr); break;
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_CASE, ())
#undef CALL_PRINT_ARRAY_CASE
default:
fprintf(stderr, "Array size is too big for what we're prepared\n");
return -1;
}
return 0;
}
int main()
{
//int a1[5] = {1,2,3,4,5};
//call_print_array(a1, sizeof(a1)/sizeof(a1[0]));
size_t size;
scanf("%zu", &size); // insecure
int * a2 = calloc(size, sizeof(*a2));
for (size_t i = 0; i < size; ++i)
a2[i] = i;
call_print_array(a2, size);
return 0;
}