开发者

C/C++ va_arg - Is there a way to skip an argument?

I am wanting to add functionality to sprintf(). Specifically, I want to be able to pass my own POD data types to it, but I am unsure of how to do this.

Supposedly, if you create the va_list, you can pass it off to vsprintf() and have it do the hard work for you - but I still need to access the va_list,开发者_如何学Go and extract items myself before passing the va_list to vsprintf().

For example, assume the following code:

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

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

With the new %z code corresponding to my new data type.

I understand only pointers and POD structures can be passed, that's no big deal. I am wondering, though, that what happens if I get to the end of the va_list (by getting the args using va_arg()) and then pass it to vsprintf()?

Thank you!


Given that va_arg must be called in the right order and with the right type for proper behavior I think you have to consume the fmt piecemeal while processing the parts you care about and passing the rest to 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, "!");

In my example I just took | to be like %d but a real example with additional %... escapes will be much more complex.


Make two va_lists and use only one to do what you need to do, then pass the other one to vsprintf or whatever:

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*/);

Remember that a va_list is really only a pointer to a place on the stack (it's implementation-specific I guess, but that's how it is where I come from). va_arg returns the thing pointed to by the va_list casted to the specified type, and increments the pointer by sizeof(thetype). So if you get two pointers and keep one without modifying it, you can just pass that to another function.

I hope I didn't misunderstand the question.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜