【问题标题】:How to use __VA_ARGS__ inside a C function instead of macro? [duplicate]如何在 C 函数而不是宏中使用 __VA_ARGS__? [复制]
【发布时间】:2011-05-19 08:56:49
【问题描述】:

可能重复:
C/C++: Passing variable number of arguments around

我目前正在使用在我的 C 文件中声明的以下宏。

#define COMMON_Print(...) printf (__VA_ARGS__)

现在调用工作正常,但事实证明我需要能够创建一个看起来像这样的 C 函数:

void COMMON_Print(...)
{    
    printf (__VA_ARGS__);
}

所以那个功能不起作用,我得到一个错误

“错误:未定义的标识符 __VA_ARGS__”

我的项目的复杂性需要一个函数,因为它是一个接口......那么我怎样才能获取参数......并将它们传递给 printf 函数?或者更好的是我做错了什么?

谢谢!

【问题讨论】:

标签: c


【解决方案1】:

__VA_ARGS__ 仅适用于宏。

不能直接将可变数量的参数链接到另一个函数。相反,你必须 传递一个 va_list ,您调用的函数必须采用 va_list。幸运的是,有一个 printf 的变体可以做到这一点,你的函数必须这样写:

void COMMON_Print(char *format,...)
{    
  va_list args;
  va_start(args,format);
  vprintf(format,args);
  va_end(args);
}

【讨论】:

  • 非常感谢您的回复!它确实有效!但是我相信我需要解决一些格式问题。仅供参考,我正在开发嵌入式设备。
  • 什么是 vaprintf ?还是只是一个错字?
  • 此代码示例中有两个错误。第一次呼叫应该是va_start 而不是va_begin,第二次呼叫是vprintf 而不是vsprintf
【解决方案2】:

您正在寻找的是Ellipsis 运算符。

【讨论】:

    【解决方案3】:

    __VA_ARGS__ 仅适用于宏;可变参数函数是相当不同的。您需要使用stdarg.h 中的va_startva_argva_end 来处理它们。

    首先,您的函数至少需要一个命名参数,例如:

    void COMMON_Print(const char* fmt, ...)
    

    然后你可以定义一个va_list并使用va_start来设置它:

    va_list args;
    va_start(args, fmt);
    // your code here
    va_end(args);
    

    现在您可以使用args 访问参数;调用 va_arg(args, TYPE) 将返回下一个可变参数,因此您可以继续调用它,直到您读取所有参数为止。

    如果您只是想调用printf,有一个名为vprintf 的printf 变体可以直接使用va_list

    vprintf(fmt, args);
    

    从另一个变量调用一个可变参数函数没有简单的方法;你需要像vprintf 这样的东西来占用整个va_list

    【讨论】:

    • 感谢您的解释。感谢他们真正帮助的帮助和解释! :)
    • 'va_arg(args, TYPE)' 仅当调用者传递 NULL 时才会返回 NULL。 va_arg 没有默认的结束条件。您必须传递一个标记值或知道参数的确切数量,通过参数传递或通过计算 printf 格式字符串中的 % 数量。
    • @tristopia 哦,对;我习惯在必要时最后传递 NULL。固定
    【解决方案4】:

    每个?printf 函数都有一个对应的v?printf 函数,它做同样的事情,但接受一个va_list,一个变量参数列表。

    #include <stdio.h>
    #include <stdarg.h>
    
    void COMMON_Print(char *format, ...)
    {
        va_list args;
    
        va_start(args, format);
        vprintf(format, args);
        va_end(args);
    }
    

    旁注:注意va_start... 之前的最后一个参数的名称作为参数。 va_start 是一个宏,它执行一些基于堆栈的魔法来检索变量参数,它需要最后一个固定参数的地址来执行此操作。

    因此,必须至少有一个固定参数,以便您可以将其传递给va_start。这就是为什么我添加了format 参数而不是坚持使用更简单的COMMON_Print(...) 声明。

    见:http://www.cplusplus.com/reference/clibrary/cstdio/vprintf/

    【讨论】:

    • 如果使用宏,则不需要前面的 arg。考虑这个例子:#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) 从使用的角度来看,这显然是非常方便的。
    猜你喜欢
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多