C / C ++ va_arg - 有没有办法跳过一个参数?

时间:2011-05-08 21:05:48

标签: c++ c variadic-functions

我想为sprintf()添加功能。具体来说,我希望能够将自己的POD数据类型传递给它,但我不确定如何执行此操作。

据说,如果你创建了va_list,你可以把它传递给vsprintf()并让它为你做艰苦的工作 - 但是我仍然需要访问va_list,并在将va_list传递给vsprintf之前自己提取项目( )。

例如,假设以下代码:

struct mypod {
    int somedata;
}; // just for example, you know

// somewhere else in the code...
mypod mp;
mp.somedata = 5325;
my_sprintf(myChrPtr, "%z", mp);

新的%z代码对应于我的新数据类型。

我知道只有指针和POD结构才能通过,这没什么大不了的。我想知道,如果我到达va_list的末尾(通过使用va_arg()获取args然后将其传递给vsprintf())会发生什么?

谢谢!

2 个答案:

答案 0 :(得分:1)

制作两个va_list并仅使用一个来做您需要做的事情,然后将另一个传递给vsprintf或其他:

va_list l1 = va_start(final_arg);
va_list l2 = va_start(final_arg);

// do stuff with l1 and l2 will be unaffected

vsprintf(/*using l2*/);

请记住,va_list实际上只是指向堆栈上某个位置的指针(我猜这是特定于实现的,但这就是我来自哪里)。 va_arg返回va_list所指向的指定类型的指针,并将指针递增sizeof(thetype)。因此,如果你得到两个指针并保持一个而不修改它,你可以将它传递给另一个函数。

我希望我没有误解这个问题。

答案 1 :(得分:1)

鉴于必须以正确的顺序调用va_arg并使用正确的类型才能正确行为,我认为您必须在处理您关注的部分时将fmt零碎,并将其余部分传递给vsprintf

void
mysprintf(char *dst, char *fmt, ...)
{
    char *p = fmt;
    va_list va;

    va_start(va, fmt);
    do {
        char *q = strchr(p, '|');
        if (q) {
            /* really should take const char *fmt and not write on it like this... */
            *q++ = '\0';
        }
        dst += vsprintf(dst, p, va);  /* let vsprintf do a subset */
        if (q) {
            dst += sprintf(dst, "%d", va_arg(va, int));  /* consume 1 int */
        }
        p = q;
    } while (p);

    va_end(va);
}


strcpy(fmt, "%s|%s|%s");  /* mutable fmt */
mysprintf(buf, fmt, "hello", 7, "world", 8, "!");

在我的示例中,我只是将|变为%d,但是一个带有额外%...转义的真实示例将会复杂得多。