va_list与vsnprintf

  • VA_LIST
    • 变量
    • 用法
    • 注意问题
  • vsnprintf
    • 描述
    • 参数
    • 返回值
    • 例子
    • 类比
  • 参考文献

VA_LIST

VA_LIST 是在C语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数。可变参数通常在函数参数列表的末尾使用省略号(,…)定义。

变量

va_list 这是一个适用于 va_start()、va_arg()va_end() 这三个宏存储信息的类型

#ifdef _M_ALPHA
typedef struct {char *a0;   /* pointer to first homed integer argument */int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
/// _M_ALPHA是指DEC ALPHA(Alpha AXP)架构。所以一般情况下va_list所定义变量为字符指针。

描述
VA_START void va_start(va_list ap, last_arg)
这个宏初始化 ap 变量,它与 va_argva_end 宏是一起使用的。last_arg 是最后一个传递给函数的已知的固定参数,即省略号之前的参数。
VA_ARG type va_arg(va_list ap, type)
这个宏检索函数参数列表中类型为 type 的下一个参数。
VA_END void va_end(va_list ap)
这个宏允许使用了 va_start 宏的带有可变参数的函数返回。如果在从函数返回之前没有调用 va_end,则结果为未定义。

INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

VA_END宏,清空va_list可变参数列表:

#define va_end(ap) ( ap = (va_list)0 )

用法

  1. 首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
  2. 然后用VA_START宏初始化刚定义的VA_LIST变量;
  3. 然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
  4. 最后用VA_END宏结束可变参数的获取。

注意问题

  1. 可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不同参数的个数和类型;
  2. 如果我们不需要一一详解每个参数,只需要将可变列表拷贝至某个缓冲,可用vsprintf函数;
  3. 因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码;

vsnprintf

vsnprintf定义在库文件<cstdio>中。

int vsnprintf (char * s, size_t n, const char * format, va_list arg );

描述

功能:将格式化数据从可变参数列表写入指定大小的缓冲区(Write formatted data from variable argument list to sized buffer)

用法:format参数用法类似于printf,使用和printf相同的格式化参数并且用于将格式化后的文本组成一个字符串。但是使用由arg标识的变量参数列表中的元素而不是其他函数参数,并将结果内容作为C字符串存储在s指向的缓冲区中(以n作为要填充的最大缓冲区容量)。

Composes a string with the same text that would be printed if format was used on printf, but using the elements in the variable argument list identified by arg instead of additional function arguments and storing the resulting content as a C string in the buffer pointed by s (taking n as the maximum buffer capacity to fill).

如果结果字符串大于n-1个字符,则剩余的字符将被丢弃且不存储,但会计入函数返回的值。

If the resulting string would be longer than n-1 characters, the remaining characters are discarded and not stored, but counted for the value returned by the function.

在内部,该函数从arg标识的列表中检索参数,类似于va_arg

Internally, the function retrieves arguments from the list identified by arg as if va_arg was used on it, and thus the state of arg is likely to be altered by the call.

在任何情况下,arg都应该在调用之前的某个点由va_start初始化,并且预计在调用之后的某个点由va_end释放。

In any case, arg should have been initialized by va_start at some point before the call, and it is expected to be released by va_end at some point after the call.

参数

  • s
    指向存储结果C字符串的缓冲区的指针。
    缓冲区的大小至少应为n个字符。
    Pointer to a buffer where the resulting C-string is stored. The buffer should have a size of at least n characters.

  • n
    要在缓冲区中使用的最大字节数。生成的字符串的长度最多为n-1,为额外的终止空字符留出空间。size_t是无符号整数类型。
    Maximum number of bytes to be used in the buffer. The generated string has a length of at most n-1, leaving space for the additional terminating null character. size_t is an unsigned integral type.

  • format
    格式化参数
    C string that contains a format string that follows the same specifications as format in printf (see printf for details).

  • arg
    标识用va_start初始化的变量参数列表的值。va_list是在 中定义的特殊类型。
    A value identifying a variable arguments list initialized with va_start. va_list is a special type defined in .

返回值

如果n足够大,将返回写入的字符数,不计算终止空字符。
如果发生编码错误,则返回负数。
注意,只有当这个返回值是非负且小于n 时,字符串才被完全写入。

The number of characters that would have been written if n had been sufficiently large, not counting the terminating null character.
If an encoding error occurs, a negative number is returned.
Notice that only when this returned value is non-negative and less than n, the string has been completely written.

例子

/* vsnprintf example */
#include <stdio.h>
#include <stdarg.h>void PrintFError ( const char * format, ... )
{char buffer[256];va_list args;va_start (args, format);vsnprintf (buffer,256,format, args);perror (buffer);va_end (args);
}int main ()
{FILE * pFile;char szFileName[]="myfile.txt";pFile = fopen (szFileName,"r");if (pFile == NULL)PrintFError ("Error opening '%s'",szFileName);else{// file successfully openfclose (pFile);}return 0;
}

在此示例中,如果文件myfile.txt不存在,则调用perror以显示类似于以下内容的错误消息:
打开文件“myfile.txt”时出错:没有这样的文件或目录

In this example, if the file myfile.txt does not exist, perror is called to show an error message similar to:
Error opening file ‘myfile.txt’: No such file or directory

类比

#include <stdio.h>
int printf(const char *format, ...);                // 输出到标准输出
int fprintf(FILE *stream, const char *format, ...); // 输出到文件
int sprintf(char *str, const char *format, ...);    // 输出到字符串str中
int snprintf(char *str, size_t size, const char *format, ...); // 按size大小输出到字符串str中// 以下函数功能与上面的一一对应相同,只是在函数调用时,把上面的...对应的一个个变量用va_list调用所替代。在函数调用前ap要通过va_start()宏来动态获取。
#include <stdarg.h>
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

参考文献

百度百科:va_list

cplusplus.com

CSDN

CSDN

菜鸟教程

va_list与vsnprintf相关推荐

  1. va_list和vsnprintf、getopt

    原理解释: VA_LIST 是在C语言中解决变参问题的一组宏,在<stdarg.h>头文件下. VA_LIST的用法:            (1)首先在函数里定义一具VA_LIST型的变 ...

  2. vsnprintf linux,va_list和vsnprintf

    原理解释: VA_LIST 是在C语言中解决变参问题的一组宏,在头文件下. VA_LIST的用法: (1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针 (2)然后用VA_STA ...

  3. 理解可变参数va_list、va_start、va_arg、va_end原理及使用方法

     参考: http://www.360doc.com/content/12/0309/10/4025635_192940551.shtml http://www.cnblogs.com/Annie ...

  4. Printf全家桶,fprintf、sprintf等

    Printf全家桶 一.printf 二.fprintf 三.dprintf 四.sprintf 五.snprintf 六.vprintf 七.vfprintf 八.vdprintf 九.vsprin ...

  5. c语言格式化字符串,C语言格式化输出小结

    函数说明 在gcc编程中,我们常用到的字符格式化输出函数是printf的,实际上gcc继承了C语言处理字符具有强大功能的风格,它提供了一系列的格式化输出函数,主要存在两个库函数文件stdio.h/ s ...

  6. stetho 调试数据库_stetho是适用于android应用程序的最佳调试工具

    stetho 调试数据库 As Android developers, our development life often involves integrating API or web servi ...

  7. LCC编译器的源程序分析(2)LCC编译器的预处理

    上面已经介绍了 C 编译器的目标,其实在实现这个目标之前,是经历了很多阶段处理的,其中第一个阶段的处理,就是预处理.预处理的任务是做什么呢?在 LCC 里预处理主要是把所有包含的头文件和源程序生成一个 ...

  8. C/C++vsnprintf用法(要配合va_list使用)

    _vsnprintf是C语言库函数之一,属于可变参数.用于向字符串中打印数据.数据格式用户自定义.头文件是#include <stdarg.h>. 参数说明: char *str [out ...

  9. vsnprintf va_list va_start va_end

    1.函数原型: int vsnprintf(char *str, size_t size, const char *format, va_list ap); 某度百科: _vsnprintf是C语言库 ...

最新文章

  1. 【机器学习基础】深入讨论机器学习 8 大回归模型的基本原理以及差异!
  2. python数据生成正态分布图_Python 与金融数据生成机器学习的特征数据
  3. C#使用Newtonsoft.Json读写json、读写Base64图像
  4. CentOS6.5 安装Tomcat6
  5. 魔兽争霸3冰封王座,打不开,提示“此版本之魔兽争霸3需要特定语言版本之windows“
  6. linux怎么踢普通用户,Linux系统管理员踢用户的方法
  7. 李飞飞计算机视觉课程CS231n总结
  8. 类似微信5.x朋友圈的弹出框评论功能
  9. Python爬取《扫黑风暴》腾讯视频弹幕
  10. windows 7 UEFI 启动模式安装,解决win7 64 setup会提示GPT分区不支持的问题
  11. LabVIEW学习(一):认识LabVIEW
  12. 修复移动硬盘“文件或目录损坏且无法读取”错误
  13. java 魔法数_魔法数字与常量定义
  14. 在ubuntu系统下使用gcc和makefile实现c语言程序的编译运行
  15. [vim与gvim技巧]vimgvim技巧大全(1)
  16. 顺丰菜鸟之争落幕:今日12时起恢复数据传输
  17. LaTeX技巧心得28:如何在文中实现带圈的数字和圈中加号
  18. MySQL分别通过Navicat附加mdf文件,Workbench导入sql文件
  19. eureka配置账号密码才能访问
  20. 虚幻4退出游戏蓝图节点

热门文章

  1. JS全排列的几种算法
  2. 三维重建领域_常用算法简介
  3. DOMBOM移动端事件jQuery
  4. Linux的init系统:sysvinit,upstart,systemd
  5. 数据结构三要素——逻辑结构和物理结构与数据运算之间的关系
  6. 如果把谷歌数据中心的数据都用打孔卡存起来
  7. logstash实现mysql数据库表实时同步
  8. 年轻小伙依靠刺绣增收致富
  9. 基于开路电压测量(OCV)的电量计获取锂离子(Li+)电池参数
  10. Web 应用程序报告: 启用了不安全的“OPTIONS”HTTP 方法 建议:禁用 WebDAV,或者禁止不需要的 HTTP 方法 spring boot