Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 平台与vsprintf和va_列表不一致_C_Variadic Functions_Printf - Fatal编程技术网

C 平台与vsprintf和va_列表不一致

C 平台与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

背景:我目前正在尝试“扩展”标准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,因此它打印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);
}
#包括
#包括
#包括
#包括
静态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
版本),并为该说明符提供一个格式字符串(显然对于
%@
,您可以截取并执行自己的操作)。