Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.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 va_列表的重用_C_Visual Studio 2005_Printf - Fatal编程技术网

C va_列表的重用

C va_列表的重用,c,visual-studio-2005,printf,C,Visual Studio 2005,Printf,我需要在va_列表上进行两次(或更多)传递。我有一个一定大小的缓冲区,我想在其中写入一个带sprintf的格式化字符串。如果格式化字符串不适合分配的空间,我希望将分配的空间加倍并重复,直到合适为止 (作为旁注,我希望能够首先计算格式化字符串的长度并分配足够的空间,但我发现唯一可以做到这一点的函数是_snprintf,它在VS2005中被弃用…) 现在,到目前为止还没有问题:我使用vsnprintf并在每次调用之前调用va_start 但我还创建了一个函数,它将va_list作为参数,而不是“…”

我需要在
va_列表上进行两次(或更多)传递。我有一个一定大小的缓冲区,我想在其中写入一个带sprintf的格式化字符串。如果格式化字符串不适合分配的空间,我希望将分配的空间加倍并重复,直到合适为止

(作为旁注,我希望能够首先计算格式化字符串的长度并分配足够的空间,但我发现唯一可以做到这一点的函数是_snprintf,它在VS2005中被弃用…)

现在,到目前为止还没有问题:我使用
vsnprintf
并在每次调用之前调用
va_start

但我还创建了一个函数,它将
va_list
作为参数,而不是“…”。然后我不能再使用
va_start
!我读过关于
va_copy
,但VS2005不支持它

那么,您将如何做到这一点呢?

我认为没有可移植的方式(我认为在C99中引入了va_copy,因为在c89中没有可移植的方式来实现其结果)。va_列表可以是声明为

typedef struct __va_list va_list[1];
(另一个使用该技巧的用户请参见gmp),这就解释了他们周围的许多语言限制。顺便说一句,如果可移植性很重要,请不要忘记va_端

如果可移植性不重要,我会检查stdard.h,看看我是否可以根据真实的声明修改一些东西。

关于MSVC中缺少
va_copy
的问题,我有一些相当不错的建议,包括实现自己版本的
va_copy
,以便在MSVC中使用:

#define va_copy(d,s) ((d) = (s))
您可能希望将其放入一个“可移植性”标题中,该标题由一个
#ifndef va_copy
#ifdef MSC_VER
保护,以便在VC上使用。

va#u copy()应该是C99规范的一部分;与所有可变参数一样,参数支持非常依赖于平台。中定义了va_列表、va_复制()、va_开始()、va_结束()宏

GCC:当试图在GCC上重用va_列表时,必须使用va_copy(),因为GCC实现会导致va_列表被修改,从而导致指针位于v??printf()函数使用后的最后一个参数之后

SUN:尝试在SunStudio(v11、v12)中重用va_列表时,va_列表变量未被触及,可以根据需要多次重用,而无需va_copy()

MS_Visual C:不确定,但看起来2010年VC++文档确实提到了“va_copy()”,这可能意味着对va_列表的重用是合理的,但应该进行测试

例如:

#include <stdio.h>
#include <stdarg.h>
/**
 * Version of vsprintf that dynamically resizes the given buffer to avoid overrun.
 * Uses va_copy() under GCC compile.
 **/    
int my_vsprintf(char **buffer, char *msg, va_list args)
{
   int bufLen = 0;
   va_list dupArgs;       // localize args copy

#ifdef __GNUC__
   va_copy(dupArgs,args); // Clone arguments for reuse by different call to vsprintf.
#else 
   dupArgs = args;        // Simply ptr copy for GCC compatibility
#endif

   // Perform 1st pass to calculate required buffer size.  The vsnprintf() funct
   // returns the number of chars (excluding \0 term) necessary to produce the output.
   // Notice the NULL pointer, and zero length.
   bufLen = vsnprintf(NULL,0,msg, dupArgs); 

   // NOTE: dupArgs on GCC platform is mangled by usage in v*printf() and cannot be reused.
#ifdef __GNUC__
   va_end(dupArgs); // cleanup 
#endif

   *buffer = realloc(*buffer,bufLen + 1);  // resize buffer, with \0 term included.

#ifdef __GNUC__
   va_copy(dupArgs,args); // Clone arguments for reused by different call to vsprintf.
#endif

   // Perform 2nd pass to populate buffer that is sufficient in size,
   // with \0 term size included.
   bufLen = vsnprintf(buffer, bufLen+1, msg, dupArgs);

   // NOTE: dupArgs on GCC platform is mangled by usage in v*printf() and cannot be reused.
#ifdef __GNUC__
   va_end(dupArgs); // cleanup
#endif

   return(bufLen);  // return chars written to buffer.
}

/**
 * Version of sprintf that dynamically resizes the given buffer to avoid buffer overrun
 * by simply calling my_vsprintf() with the va_list of arguments.
 *
 * USage:
 **/
int my_sprintf(char **buffer, char *msg, ...)
{
    int bufLen = 0;
    va_list myArgs; 

    va_start(myArgs, msg);   // Initialize myArgs to first variadic parameter.

    // re-use function that takes va_list of arguments.       
    bufLen = my_vsprintf(buffer, msg, myArgs ); 

    va_end(myArgs);
} 
#包括
#包括
/**
*动态调整给定缓冲区大小以避免溢出的vsprintf版本。
*在GCC compile下使用va_copy()。
**/    
int my_vsprintf(字符**缓冲区,字符*消息,va_列表参数)
{
int-bufLen=0;
va_list dupArgs;//本地化args副本
#ifdef__GNUC__
va_copy(dupArgs,args);//克隆参数以便通过对vsprintf的不同调用重用。
#否则
dupArgs=args;//只需ptr拷贝即可实现GCC兼容性
#恩迪夫
//执行第1步以计算所需的缓冲区大小。vsnprintf()函数
//返回生成输出所需的字符数(不包括\0项)。
//请注意空指针和零长度。
bufLen=vsnprintf(NULL,0,msg,dupArgs);
//注意:GCC平台上的dupArgs因在v*printf()中的使用而损坏,无法重用。
#ifdef__GNUC__
va_end(dupArgs);//清除
#恩迪夫
*buffer=realloc(*buffer,bufLen+1);//调整缓冲区大小,包括\0术语。
#ifdef__GNUC__
va_copy(dupArgs,args);//克隆参数以供对vsprintf的不同调用重用。
#恩迪夫
//执行第二遍以填充足够大的缓冲区,
//包含\0术语大小。
bufLen=vsnprintf(缓冲区,bufLen+1,msg,dupArgs);
//注意:GCC平台上的dupArgs因在v*printf()中的使用而损坏,无法重用。
#ifdef__GNUC__
va_end(dupArgs);//清除
#恩迪夫
return(bufLen);//返回写入缓冲区的字符。
}
/**
*动态调整给定缓冲区大小以避免缓冲区溢出的sprintf版本
*只需使用va_参数列表调用my_vsprintf()。
*
*用法:
**/
int my_sprintf(字符**缓冲区,字符*消息,…)
{
int-bufLen=0;
va_列表myArgs;
va_start(myArgs,msg);//将myArgs初始化为第一个可变参数。
//重复使用函数,该函数接受一系列参数。
bufLen=my_vsprintf(缓冲区、msg、myArgs);
va_end(myArgs);
} 

回复很晚,但希望有人会发现这很有用。 我需要使用va_copy,但在vc2005中无法使用,我在这一页上搜索并找到了自己

我有点担心使用看似粗糙的:

va_copy(d,s) ((d) = (s))
所以我在附近挖了一下。我想看看va_copy是如何在vc2013中实现的,所以我编译了一个使用va_copy的测试程序并对其进行了反汇编:

首先,根据msdn使用:

void va_copy(
   va_list dest,
   va_list src
); // (ISO C99 and later)
拆卸msvcr120中实施的va_副本(全部7行!):

如您所见,它实际上非常简单,只需在解析之前将src va_列表的值分配给dest va_列表

由于我只使用ms编译器,并且目前使用vc2005,将来可能会进行升级,因此我使用的是:

#if _MSC_VER < 1800 // va_copy is available in vc2013 and onwards
#define va_copy(a,b) (a = b)
#endif
\if\u MSC\u VER<1800//va\u副本在vc2013及以后版本中可用
#定义虚拟副本(a,b)(a=b)
#恩迪夫

Ok。如果没有答案,那也是答案。谢谢
#if _MSC_VER < 1800 // va_copy is available in vc2013 and onwards
#define va_copy(a,b) (a = b)
#endif