C 平台与vsprintf和va_列表不一致
背景:我目前正在尝试“扩展”标准C格式,以支持处理特定结构,类似于Objective-C如何扩展C格式以支持带有“%@”序列的NSString 我正在努力解决的一个问题是,vsprintf在OSX和Linux上的表现似乎有所不同(我已经用Ubuntu 10.10和12.04进行了测试)。在OSX上,它的行为符合我的想法,在调用vsprintf之后,调用va_arg返回ms指针(好像vsprintf函数调用va_arg来获取5)。但是,在Linux上,va_列表不会从vsprintf更改,调用va_arg返回5 我真的很想找到一种实现此功能的方法,以便它在不同平台上保持一致的行为。假设vsprintf可以一致地更改va_列表中的指针,以便下次调用va_arg时返回下一个尚未使用的参数,这是错误的吗 我已经尽可能地简化了我的代码来演示这个问题。在OSX上,此代码打印从malloc返回的指针的正确地址。在Linux上,foo中ms的值变为5,因此它打印5C 平台与vsprintf和va_列表不一致,c,variadic-functions,printf,C,Variadic Functions,Printf,背景:我目前正在尝试“扩展”标准C格式,以支持处理特定结构,类似于Objective-C如何扩展C格式以支持带有“%@”序列的NSString 我正在努力解决的一个问题是,vsprintf在OSX和Linux上的表现似乎有所不同(我已经用Ubuntu 10.10和12.04进行了测试)。在OSX上,它的行为符合我的想法,在调用vsprintf之后,调用va_arg返回ms指针(好像vsprintf函数调用va_arg来获取5)。但是,在Linux上,va_列表不会从vsprintf更改,调用va
#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);
}
#包括
#包括
#包括
#包括
静态void foo(void*,…);
类型定义结构{
字符*值;
}我的结构;
int main(int argc,char*argv[]){
mystruct*ms=malloc(sizeof(mystruct));
foo(空,“%d%@”,5,毫秒);
}
void foo(void*dummy,…){
va_列表参数;
va_启动(args,dummy);
字符缓冲区[512];
int buffer_ptr=0;
int i=0;
char*format=va_arg(args,char*);
缓冲区[0]='\0';
对于(i=0;i
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);
问题是如何实现va_列表
,取决于实现——它可能包含直接提取参数的所有信息和状态,或者可能包含指向间接保存状态的某个对象的指针。因此,将其传递给vsprintf可能会复制所有相关状态,也可能不会
您想要做的是一个类似vspintf的函数,它采用va_列表*
,而不是va_列表
,因此您可以确保它返回后处于正确的状态。不幸的是,该标准没有提供任何此类函数。:“当这些函数调用va_arg
宏时,返回后ap
的值未指定。”(ap
是va_列表
)我现在明白了。谢谢。这是实现我真正想要编写的自定义vsprintf的唯一方法,我可以依靠它的行为来使用va_列表,这样foo中的ms变量就可以设置为正确的值了吗?嗯,我不认为有一个简单的答案。如果你想要完全可移植的代码,你可能需要遍历格式字符串并解析每个字符串格式说明符:对于每个可能的格式说明符,使用va_arg
获取正确的数据类型,然后将其传递给sprintf
(非v
版本),并为该说明符提供一个格式字符串(显然对于%@
,您可以截取并执行自己的操作)。