我想为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())会发生什么?
谢谢!
答案 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
,但是一个带有额外%...
转义的真实示例将会复杂得多。