[英]Passing variable args from macro to a function that expects va_list
#define exampleA(buf, args...) \
exampleB(buf, ##args); \
}
#endif
works where the exampleB function declaration is exampleB(char* buf, ...).在 exampleB function 声明为 exampleB(char* buf, ...) 的情况下工作。 But I need to change the declaration as exampleB(char* buf, va_list args).
但我需要将声明更改为 exampleB(char* buf, va_list args)。 How can change the marco accordingly?
如何相应地更改marco?
You cannot.你不能。 In order to create a
va_list
, you need to have a variadic function.为了创建
va_list
,您需要有一个可变参数 function。 There is no portable facility to create a va_list
object from a list of arguments.没有可移植的工具来从 arguments 的列表中创建
va_list
object。
It is quite common to write variadic functions in pairs: the outer function uses the facilities in <stdarg.h>
to construct a va_list
, and it passes that list directly to the function which does the work.成对编写可变参数函数是很常见的:外部 function 使用
<stdarg.h>
中的设施来构造一个va_list
,并将该列表直接传递给完成工作的 function 。 You see that in the standarid I/O library, for example: printf
/ vprintf
, fprintf
/ vfprintf
, snprintf
/ vsnprintf
, scanf
/ vscanf
, etc.您可以在标准 I/O 库中看到,例如:
printf
/ vprintf
、 fprintf
/ vfprintf
、 snprintf
/ vsnprintf
、 scanf
/ vscanf
等。
And that's what you should do for your problem: write exampleB
as the va_list
form of exampleA
.这就是你应该为你的问题做的:将
exampleB
写为exampleA
的va_list
形式。
Here, for example, is the entire implementation of the fprintf
function extrated from the FreeBSD library, which can serve as a model of this style:例如,这里是从 FreeBSD 库中提取的
fprintf
function 的完整实现,它可以用作这种风格的 model:
int
fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf_l(fp, __get_locale(), fmt, ap);
va_end(ap);
return (ret);
}
As you can see from that snippet, vfprintf_l
(which takes a locale argument) is actually the implementation;正如您从该片段中看到的那样,
vfprintf_l
(它接受一个语言环境参数)实际上是实现; all the other *printf
functions are simple wrappers.所有其他
*printf
函数都是简单的包装器。 ( printf
, for examples, calls vfprintf_l
passing stdin
and the locale argument.) That avoids having to traverse multiple wrappers in a single call, although modern optimising compilers are usually able to do that elimination automatically. (
printf
,调用vfprintf_l
传递stdin
和 locale 参数。)这避免了必须在单个调用中遍历多个包装器,尽管现代优化编译器通常能够自动进行消除。
(See lib/libc/stdio/fprintf.c for the full file in the FreeBSD source repository mirror on Github.) (请参阅lib/libc/stdio/fprintf.c以获取 Github 上 FreeBSD 源存储库镜像中的完整文件。)
Speaking of portability, #define exampleA(buf, args...)
is a GCC extension which is not portable to most C implementations (although Clang implements it as well).说到可移植性,#define exampleA
#define exampleA(buf, args...)
是一个 GCC 扩展,它不能移植到大多数 C 实现中(尽管 Z9375884CF4ED31C834A626C324DDDC6 实现它) You should use __VA_ARGS__
as per standard C:您应该按照标准 C 使用
__VA_ARGS__
:
#define exampleA(buf, ...) \
exampleB(buf, ## __VA_ARGS__)
Even better, if you can, replace the other GCC extension ( , ##
) with the newer standard __VA_OPT__
:更好的是,如果可以的话,用更新的标准
__VA_OPT__
替换其他 GCC 扩展( , ##
):
#define exampleA(buf, ...) \
exampleB(buf __VA_OPT__(,) __VA_ARGS__)
I don't think this is possible the way you imagine it.我认为这不可能像你想象的那样。 Let's consider a function
exampleX(char *,...)
: the arguments you pass must live somewhere and let's say they are pushed to the stack.让我们考虑一个 function
exampleX(char *,...)
:您传递的 arguments 必须存在于某个地方,假设它们被推入堆栈。 The va_list
macros know that and can access them from there. va_list
宏知道这一点并且可以从那里访问它们。 The moment you leave that function, the arguments cannot be assumed to be on the stack anymore.当您离开 function 时,不能再假定 arguments 在堆栈上。
Thus, you may not write a helper function like va_list getArgs(char*x,...) { /* use va_start and return the va_list */ }
and pass that va_list
to exampleB
.因此,您可能不会像
va_list getArgs(char*x,...) { /* use va_start and return the va_list */ }
并将该va_list
传递给exampleB
那样编写帮助程序 function 。
The only thing I can think of is to write a trampoline function such as我唯一能想到的就是写一个蹦床 function 比如
void callExampleB(char * buf, ...) {
va_list ap;
va_start(ap, buf);
exampleB(buf, ap);
va_end(ap);
}
and call that in your macro.并在你的宏中调用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.