gpt4 book ai didi

c - 与 vsprintf 和 va_list 的平台不一致

转载 作者:太空狗 更新时间:2023-10-29 15:30:06 24 4
gpt4 key购买 nike

背景:我目前正在尝试“扩展”标准 C 格式,以支持处理特定结构,类似于 Objective-C 扩展 C 格式以允许使用“%@”序列支持 NSString 的方式。

我遇到的一个问题是 vsprintf 在 OS X 和 Linux 上的表现似乎不同(我已经用 Ubuntu 10.10 和 12.04 测试过)。在 OS X 上,它的行为符合我的预期,在调用 vsprintf 之后,调用 va_arg 返回 ms 指针(就好像 vsprintf 函数调用 va_arg 来获取 5)。然而,在 Linux 上,va_list 不会从 vsprintf 改变,并且调用 va_arg 返回 5。

我真的很想找出一种方法来实现此功能,以便它在各个平台上表现一致。假设您可以期望 vsprintf 始终更改 va_list 中的指针以便下次调用 va_arg 时它返回下一个尚未使用的参数,这是错误的吗?

我已经尽可能地简化了我的代码来演示这个问题。在 OS X 上,此代码打印从 malloc 返回的指针的正确地址。在 Linux 上,foo 中的 ms 值变为 5,因此它打印 5。

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

static void foo(void *, ...);

typedef struct {
char *value;
} mystruct;

int main(int argc, char *argv[]) {
mystruct *ms = malloc(sizeof(mystruct));
foo(NULL, "%d %@", 5, ms);
}

void foo(void *dummy, ...) {
va_list args;
va_start(args, dummy);
char buffer[512];
int buffer_ptr = 0;
int i = 0;
char *format = va_arg(args, char *);

buffer[0] = '\0';

for (i = 0; i < strlen(format); i++) {
if (i <= strlen(format) - 1 && (format[i] == '%' && format[i+1] == '@')) {
vsprintf(buffer, buffer, args);

/* can expect the next argument to be a mystruct pointer */
mystruct *ms = va_arg(args, mystruct *);
buffer[buffer_ptr+1] = '\0';
fprintf(stderr, "%p", ms); /* SHOULD NOT PRINT 5 */

/* concatenate here */
} else {
buffer[buffer_ptr++] = format[i];
buffer[buffer_ptr] = '\0';
}
}

va_end(args);
}

最佳答案

您需要使用 va_copy如果您要多次使用参数列表——不这样做是未定义的行为。您的代码应如下所示:

va_list args;
va_start(args, dummy);
...
char *format = va_arg(args, char *);
...
va_list argsCopy;
va_copy(argsCopy, args);
vsprintf(..., argsCopy);
va_end(argsCopy);
...
mystruct *ms = va_arg(args, mystruct *);
...
va_end(args);

关于c - 与 vsprintf 和 va_list 的平台不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10807310/

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