简体   繁体   English

将变量 args 从宏传递到需要 va_list 的 function

[英]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 / vprintffprintf / vfprintfsnprintf / vsnprintfscanf / vscanf等。

And that's what you should do for your problem: write exampleB as the va_list form of exampleA .这就是你应该为你的问题做的:将exampleB写为exampleAva_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM