在C中,是否有可能转发可变函数的调用?如,

int my_printf(char *fmt, ...) {
    fprintf(stderr, "Calling printf with fmt %s", fmt);
    return SOMEHOW_INVOKE_LIBC_PRINTF;
}

在这种情况下,以上述方式转发调用显然不是严格必要的(因为您可以以其他方式记录调用,或使用vfprintf),但我正在处理的代码库要求包装器做一些实际工作,并且没有(也不可能添加)类似于vfprintf的帮助函数。

[更新:根据目前提供的答案,似乎有一些困惑。用另一种方式来表达这个问题:一般来说,你可以在不修改函数定义的情况下包装任意的变进函数吗?


当前回答

基本上有三种选择。

一种是不传递它而是使用目标函数的变进实现而不传递椭圆。另一种方法是使用可变宏。第三个选择是我所缺少的所有东西。

我通常选择第一种,因为我觉得这真的很容易处理。选项二有一个缺点,因为调用可变宏有一些限制。

下面是一些示例代码:

#include <stdio.h>
#include <stdarg.h>

#define Option_VariadicMacro(f, ...)\
    printf("printing using format: %s", f);\
    printf(f, __VA_ARGS__)

int Option_ResolveVariadicAndPassOn(const char * f, ... )
{
    int r;
    va_list args;

    printf("printing using format: %s", f);
    va_start(args, f);
    r = vprintf(f, args);
    va_end(args);
    return r;
}

void main()
{
    const char * f = "%s %s %s\n";
    const char * a = "One";
    const char * b = "Two";
    const char * c = "Three";
    printf("---- Normal Print ----\n");
    printf(f, a, b, c);
    printf("\n");
    printf("---- Option_VariadicMacro ----\n");
    Option_VariadicMacro(f, a, b, c);
    printf("\n");
    printf("---- Option_ResolveVariadicAndPassOn ----\n");
    Option_ResolveVariadicAndPassOn(f, a, b, c);
    printf("\n");
}

其他回答

使用函数:

int my_printf(char *fmt, ...) {
    va_list va;
    int ret;

    va_start(va, fmt);
    ret = vfprintf(stderr, fmt, va);
    va_end(va);
    return ret;
}

如果您没有类似于vfprintf的函数,它接受一个va_list而不是可变数量的参数,那么您就不能这样做。见http://c-faq.com/varargs/handoff.html。

例子:

void myfun(const char *fmt, va_list argp) {
    vfprintf(stderr, fmt, argp);
}

Not sure if this helps to answer OP's question since I do not know why the restriction for using a helper function akin to vfprintf in the wrapper function applies. I think the key problem here is that forwarding the variadic argument list without interpreting them is difficult. What is possible, is to perform the formatting (using a helper function akin to vfprintf: vsnprintf) and forward the formatted output to the wrapped function with variadic arguments (i.e. not modifying the definition of the wrapped function). So, here we go:

#include <stdio.h>
#include <stdarg.h>

int my_printf(char *fmt, ...)
{
    if (fmt == NULL) {
        /* Invalid format pointer */
        return -1;
    } else {
        va_list args;
        int len;

        /* Initialize a variable argument list */
        va_start(args, fmt);

        /* Get length of format including arguments */
        len = vsnprintf(NULL, 0, fmt, args);

        /* End using variable argument list */
        va_end(args);
        
        if (len < 0) {
            /* vsnprintf failed */
            return -1;
        } else {
            /* Declare a character buffer for the formatted string */
            char formatted[len + 1];

            /* Initialize a variable argument list */
            va_start(args, fmt);
            
            /* Write the formatted output */
            vsnprintf(formatted, sizeof(formatted), fmt, args);
            
            /* End using variable argument list */
            va_end(args);

            /* Call the wrapped function using the formatted output and return */
            fprintf(stderr, "Calling printf with fmt %s", fmt);
            return printf("%s", formatted);
        }
    }
}

int main()
{
    /* Expected output: Test
     * Expected error: Calling printf with fmt Test
     */
    my_printf("Test\n");
    //printf("Test\n");

    /* Expected output: Test
     * Expected error: Calling printf with fmt %s
     */
    my_printf("%s\n", "Test");
    //printf("%s\n", "Test");

    /* Expected output: %s
     * Expected error: Calling printf with fmt %s
     */
    my_printf("%s\n", "%s");
    //printf("%s\n", "%s");

    return 0;
}

我遇到了这个解。

编辑:修正由egmont指出的错误

基本上有三种选择。

一种是不传递它而是使用目标函数的变进实现而不传递椭圆。另一种方法是使用可变宏。第三个选择是我所缺少的所有东西。

我通常选择第一种,因为我觉得这真的很容易处理。选项二有一个缺点,因为调用可变宏有一些限制。

下面是一些示例代码:

#include <stdio.h>
#include <stdarg.h>

#define Option_VariadicMacro(f, ...)\
    printf("printing using format: %s", f);\
    printf(f, __VA_ARGS__)

int Option_ResolveVariadicAndPassOn(const char * f, ... )
{
    int r;
    va_list args;

    printf("printing using format: %s", f);
    va_start(args, f);
    r = vprintf(f, args);
    va_end(args);
    return r;
}

void main()
{
    const char * f = "%s %s %s\n";
    const char * a = "One";
    const char * b = "Two";
    const char * c = "Three";
    printf("---- Normal Print ----\n");
    printf(f, a, b, c);
    printf("\n");
    printf("---- Option_VariadicMacro ----\n");
    Option_VariadicMacro(f, a, b, c);
    printf("\n");
    printf("---- Option_ResolveVariadicAndPassOn ----\n");
    Option_ResolveVariadicAndPassOn(f, a, b, c);
    printf("\n");
}

差不多,使用<stdarg.h>中提供的功能:

#include <stdarg.h>
int my_printf(char *format, ...)
{
   va_list args;
   va_start(args, format);
   int r = vprintf(format, args);
   va_end(args);
   return r;
}

注意,您需要使用vprintf版本,而不是普通的printf。在这种情况下,如果不使用va_list,就无法直接调用变进函数。