gpt4 book ai didi

c - Linux 上的 va_list 错误行为

转载 作者:太空狗 更新时间:2023-10-29 16:59:13 26 4
gpt4 key购买 nike

我有一些代码可以将可变参数转换为 va_list,然后将列表传递给一个函数,然后调用 vsnprintf。这在 Windows 和 OS X 上运行良好,但在 Linux 上失败并出现奇怪的结果。

在下面的代码示例中:

#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

char *myPrintfInner(const char *message, va_list params)
{
va_list *original = &params;
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,因为 This is a test. 是 15 个字符,添加 NULL 会得到 16 .

我看过但没有涉及主题的相关主题:


对于@Mat 的回答(我正在重复使用 va_list 对象,这是不允许的),这正好与我链接到的第一个相关线程有关。所以我改为尝试使用此代码:

char *myPrintfInner(const char *message, va_list params)
{
va_list *original = &params;
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

生成的二进制文件产生与第一次完全相同的效果。


找到这个:Is GCC mishandling a pointer to a va_list passed to a function?

建议的解决方法(不能保证有效,但在实践中确实有效)是首先使用 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;
}

最佳答案

正如 Mat 指出的那样,问题在于您正在重用 va_list。如果您不想按照他的建议重组代码,您可以使用 C99 va_copy()宏,像这样:

char *myPrintfInner(const char *message, va_list params)
{
va_list copy;

va_copy(copy, params);
size_t length = vsnprintf(NULL, 0, message, copy);
va_end(copy);

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;
}

在不支持 C99 的编译器上,您可以 use __va_copy() instead or define your own va_copy() implementation (这将是不可移植的,但如果确实需要,您始终可以在头文件中使用编译器/平台嗅探)。但实际上,已经 13 年了——如今任何像样的编译器都应该支持 C99,至少如果你给它正确的选项(-std=c99 for GCC)。

关于c - Linux 上的 va_list 错误行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9937505/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com