_vsnprintf,C语言库函数之一,属于可变参数。用于向字符串中打印数据、数据格式用户自定义。
头文件:
#include <stdarg.h>
函数声明:
int _vsnprintf(char* str, size_t size, const char* format, va_list ap);
参数说明:
char *str [out],把生成的格式化的字符串存放在这里.
size_t size [in], str可接受的最大字节数,防止产生数组越界.
const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。
va_list ap [in], va_list变量. va:variable-argument:可变参数
函数功能:将可变参数格式化输出到一个字符数组。
用法类似于vsprintf,不过加了size的限制,防止了内存溢出(size为str所指的存储空间的大小)。
返回值:执行成功,返回写入到字符数组str中的字符个数(不包含终止符),最大不超过size;执行失败,返回负值,并置errno.[]
备注:
linux环境下是:vsnprintf
VC6环境下是:_vsnprintf
#include <stdio.h>
#include <stdarg.h>
int mon_log(char* format, ...)
{
char str_tmp[];
int i=;
va_list vArgList; //定义一个va_list型的变量,这个变量是指向参数的指针.
va_start (vArgList, format); //用va_start宏初始化变量,这个宏的第二个参数是第一个可变参数的前一个参 //数,是一个固定的参数.
i=_vsnprintf(str_tmp, , format, vArgList); //注意,不要漏掉前面的_
va_end(vArgList); //用va_end宏结束可变参数的获取
return i; //返回参数的字符个数中间有逗号间隔
}
//调用上面的函数
void main()
  {
  int i=mon_log("%s,%d,%d,%d","asd",,,);
  printf("%d\n",i);
  }
输出 。
asd,,,
(共9个字符,间隔符逗号计算在内)
返回值用法:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *make_message(const char *fmt, ...) {
/* 初始时假设我们只需要不超过100字节大小的空间 */
int n, size = ;
char *p;
va_list ap;
if ( (p = (char *) malloc(size*sizeof(char))) == NULL)
return NULL;
while () {
/* 尝试在申请的空间中进行打印操作 */
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
/* 如果vsnprintf调用成功,返回该字符串 */
if (n > - && n < size)
return p;
/* vsnprintf调用失败(n<0),或者p的空间不足够容纳size大小的字符串(n>=size),尝试申请更大的空间*/
size *= ; /* 两倍原来大小的空间 */
if ((p = (char *)realloc(p, size*sizeof(char))) == NULL)
return NULL;
}
}
int main() {
/* 调用上面的函数 */
char* str = make_message("%d,%d,%d,%d",,,,);
printf("%s\n",str);
free(str);
/* 输出5,6,7,8*/
return ;
}
代码在vc6.0下调试通过。
本文主要介绍va_start和va_end的使用及原理。

  在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解。

  介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 

.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表

void foo(...);
void foo(parm_list,...);
这种方式和我们以前认识的不大一样,但我们要记住这是C中一种传参的形式,在后面我们就会用到它。 .函数参数的传递原理   函数参数是以数据结构:栈的形式存取,从右至左入栈。   首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
void func(int x, float y, char z);
  那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。
  下面是 <stdarg.h> 里面重要的几个宏定义如下:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。
<Step > 在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap);
<Step > 然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数;
<Step > 然后是获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;
<Step > 获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。说白了,就是让我们的程序具有健壮性。通常va_start和va_end是成对出现。
例如 int max(int n, ...); 其函数内部应该如此实现:
#include <iostream.h>
void fun(int a, ...)
{
  int *temp = &a;
  temp++;
  for (int i = ; i < a; ++i)
  {
    cout << *temp << endl;
    temp++;
  }
}
int main()
{
  int a = ;
  int b = ;
  int c = ;
  int d = ;
  fun(, a, b, c, d);
  system("pause");
  return ;
} Output:: :获取省略号指定的参数
  在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat); //一定要“...”之前的那个参数
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
} .演示如何使用参数个数可变的函数,采用ANSI标准形式
#include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉 /*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/
int demo( char, ... );
void main( void )
{
demo("DEMO", "This", "is", "a", "demo!", "");
} /*ANSI标准形式的声明方式,括号内的省略号表示可选参数*/
int demo( char msg, ... )
{
/*定义保存函数参数的结构*/
va_list argp;
int argno = ;
char para;
   /*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/
va_start( argp, msg );
while ()
{
para = va_arg( argp, char);
if ( strcmp( para, "") == )
break;
printf("Parameter #%d is: %s\n", argno, para);
argno++;
}
va_end( argp );
/*将argp置为NULL*/
return ;
}
以上是对va_start和va_end的介绍。 最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 谢谢。 完毕。^_^

_vsnprintf 用法的更多相关文章

  1. _vsnprintf在可变参数打印中的用法

    _vsnprintf,C语言库函数之一,属于可变参数.用于向字符串中打印数据.数据格式用户自定义. 函数简介 编辑 头文件: #include <stdarg.h> 函数声明: int _ ...

  2. error C3163: “_vsnprintf”: 属性与以前的声明不一致

    这是在vs2008中遇到的错误,vs2008以前没有,vs2008以后的vs也没有. c:\program files\microsoft visual studio 9.0\vc\include\s ...

  3. EditText 基本用法

    title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...

  4. jquery插件的用法之cookie 插件

    一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...

  5. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  6. [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法

    一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...

  7. python enumerate 用法

    A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...

  8. [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结

    本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...

  9. 【JavaScript】innerHTML、innerText和outerHTML的用法区别

    用法: <div id="test">   <span style="color:red">test1</span> tes ...

随机推荐

  1. C/C++面试小知识点

    1.static有什么用途. 解答: 在函数体中,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其 ...

  2. codeforces 678D Iterated Linear Function 矩阵快速幂

    矩阵快速幂的题要多做 由题可得 g[n]=A*g[n-1]+B 所以构造矩阵  { g[n] }    =  {A   B}  * { g[n-1]} {   1   }         {0   1 ...

  3. Leave Morningstar

    Today, closed 4++ years developer life (2009.11.17-2014.02.28) in MorningStar Shenzhen Office Austra ...

  4. [Hive - LanguageManual ] ]SQL Standard Based Hive Authorization

    Status of Hive Authorization before Hive 0.13 SQL Standards Based Hive Authorization (New in Hive 0. ...

  5. 关于登录的会话控制, 终极解决方案 - chunyu

    登录是用cookie还是session实现,一直有争议,普遍认为session更安全,可是有些功能,用cookie最方便也最高效,比如“记住我一周”.   cookie还是session,我的答案是两 ...

  6. 第二百八十一、二、三天 how can I 坚持

    又是三天,真搞不懂人到底是是什么,到底想要啥,好压抑. 周五,李东勇他们来北京开年会,晚上下班,去了趟团结湖公园,好冷,快冻死了,等着他们来了,见面,感觉好亲切,晚上一块吃了个火锅,玩的很happy. ...

  7. JDBC学习笔记(1)——JDBC概述

    JDBC JDBC API是一个Java API,可以访问任何类型表列数据,特别是存储在关系数据库中的数据.JDBC代表Java数据库连接. JDBC库中所包含的API任务通常与数据库使用: 连接到数 ...

  8. Android实例-全屏显示程序(XE10+小米2)(无图)

    方法一:选中窗体->BorderStyle改为“None” 方法二: 1.下载第三方控件QAndroid.Shell 2.执行FShell.Execute('su -c mount -o rem ...

  9. POJ 2185 Milking Grid(KMP)

    Milking Grid Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4738   Accepted: 1978 Desc ...

  10. Serializable 序列化使用限制

    序列化不能跨语言 如果单纯为了传数据,完全可以被json代替.