sprintf,vsprintf,va_list的使用!

来源:互联网 发布:怎么成为淘宝模特 编辑:程序博客网 时间:2024/05/06 03:04

最近在自己在做sprintf时出现一个bug,现象是写进去的字符和想要得到的字符不对。

关键核心源代码如下:

int my_fprintf(FILE *stream, const char *format, ...)
{
 int len, ret;
 char* buf;
 buf = (char *)malloc(1024);
 va_list ap;
 va_start(ap, format);

 // We should use vsprintf instead of sprintf
 len = sprintf(buf, format, ap);

 

 va_end(ap);

 

。。。

}
追了好一阵子,最后发现是这个函数的实现不对,正确的封装应该是:

int my_fprintf(FILE *stream, const char *format, ...)
{
 int len, ret;
 char* buf;
 buf = (char *)malloc(1024);
 va_list ap;
 va_start(ap, format);

 // We should use vsprintf instead of sprintf
 len = vsprintf(buf, format, ap);

 

 va_end(ap);

 

。。。

}

 

解释如下:sprintf和vsprintf

int printf (const char * szFormat, ...) ;
第一个参数是一个格式字串,後面是与格式字串中的代码相对应的不同类型多个参数。

sprintf函式定义如下:

int sprintf (char * szBuffer, const char * szFormat, ...) ;
第一个参数是字元缓冲区;後面是一个格式字串。Sprintf不是将格式化结果标准输出,而是将其存入szBuffer。该函式返回该字串的长度。在文字模式程式设计中,

vsprintf是sprintf的一个变形,它只有三个参数。vsprintf用于执行有多个参数的自订函式,类似printf格式。vsprintf的前两个参数与sprintf相同:一个用于保存结果的字元缓冲区和一个格式字串。第三个参数是指向格式化参数阵列的指标。实际上,该指标指向在堆叠中供函式呼叫的变数。va_list、va_start和va_end巨集(在STDARG.H中定义)帮助我们处理堆叠指标。

 

 

va_list的说明:

下面是 <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 1> 在调用参数表之前,应该定义一个 va_list 类型的变量,以供后用(下面假设这个 va_list 类型变量被定义为ap);
<Step 2> 然后应该对 ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量;
<Step 3> 然后是获取参数,调用 va_arg,它的第一个参数是 ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;
<Step 4> 获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。

 

 

 

 

 

 

 

 

原创粉丝点击