我有一些代码将variadic参数转换为va_list,然后将列表传递给一个函数,然后调用vsnprintf.这在
Windows和OS X上运行良好,但在
Linux上却出现了奇怪的结果.
在以下代码示例中:
#include
#include
#include
#include
char *myPrintfInner(const char *message, va_list params)
{
va_list *original = ¶ms;
size_t length = vsnprintf(NULL, 0, message, *original);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, params);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
char *myPrintf(const char *message, ...)
{
va_list va_args;
va_start(va_args, message);
size_t length = vsnprintf(NULL, 0, message, va_args);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, va_args);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
va_end(va_args);
return final;
}
int main(int argc, char **argv)
{
char *test = myPrintf("This is a %s.", "test");
char *actual = "This is a test.";
int result = strcmp(test, actual);
if (result != 0)
{
printf("%d: Test failure!\r\n", result);
}
else
{
printf("Test succeeded.\r\n");
}
return 0;
}
第二个vsnprintf调用的输出为17,strcmp的结果为31;但我不明白为什么vsnprintf会回来17看到这是一个测试.是15个字符,添加NULL,你得到16.
我见过的相关主题,但没有解决这个话题:
使用@Mat的答案(我正在重用va_list对象,这是不允许的),这正是我链接到的第一个相关线程.所以我尝试了这个代码:
char *myPrintfInner(const char *message, va_list params)
{
va_list *original = ¶ms;
size_t length = vsnprintf(NULL, 0, message, params);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, *original);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}
其中,per the C99 spec(第7.15节中的脚注)应该有效:
It is permitted to create a pointer to a va_list and pass that pointer
to another function, in which case the original function may make
further use of the original list after the other function returns.
但我的编译器(C99模式下的gcc 4.4.5)给出了关于myPrintfInner第一行的错误:
test.c: In function ‘myPrintfInner’:
test.c:8: warning: initialization from incompatible pointer type
并且得到的二进制产生与第一次完全相同的效果.
建议的解决方法(不保证可行,但在实践中确实)是首先使用arg_copy:
char *myPrintfInner(const char *message, va_list params)
{
va_list args_copy;
va_copy(args_copy, params);
size_t length = vsnprintf(NULL, 0, message, params);
char *final = (char *) malloc((length + 1) * sizeof(char));
int result = vsnprintf(final, length + 1, message, args_copy);
printf("vsnprintf result: %d\r\n", result);
printf("%s\r\n", final);
return final;
}