#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
#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);
printf 系列函数 根据 format 参数 生成 输出内容:
* printf 和 vprintf 函数 把 输出内容 写到 stdout, 即 标准输出流;
* fprintf 和 vfprintf 函数 把 输出内容 写到 给定的 stream 流;
* sprintf, snprintf, vsprintf 和 vsnprintf 函数 把 输出内容 存放到 字符串 str 中.
TIP:
* 格式字符串 format 参数控制输出内容, 它指出怎么样把后面的参数 (或 通过stdarg) 的变长参数机制访问的参数) 转换成输出内容;这些 函数 返回 打印的 字符 数量 (不包括 字符串 结尾用的 `\0');
* snprintf 和 vsnprintf 的 输出 不会 超过 size 字节 (包括了 结尾的 `\0'), 如果因为这个限制导致 输出内容被截断, 则函数返回 -1;
* 格式字符串 (format 参数) 由 零到多个 指令 组成: 普通字符 (除 % 外)被原封不动的送到输出流;
* 每个格式转换说明都会从后面提取零到多个参数. 格式转换说明 由%字符引导开始. 参数必须正确的 对应到格式转换符 (conversion specifier) 上;
printf :
const char * format ----- 用于包含变参的格式数据
... ----- 定位随后紧邻变参在调用栈上的存储位置
[用于告知编译器将format之后的其它参数依次压入调用栈;两者使用时必须依序先后紧邻。]
vprintf:
va_list ap ----- 一个后续会指向调用栈传递过来的变参的指针
va_start(ap, format) 使用format来定位ap的指向,即传入的变参序列的首地址。
int vpf(char*fmt,...)
{
va_list argptr;
int cnt;
va_start(argptr,fmt); //第一个参数为指向可变参数字符指针的变量,第二个参数是可变参数的第一个参数,通 //常用于指定可变参数列表中参数的个数
cnt=vprintf(fmt,argptr);
va_end(argptr); //将存放可变参数字符串的变量清空
return(cnt);
}
fprintf:
vfprintf:
成功则输出字符数,出错为负值。
void log(FILE *file, const char* format, ... )
{
va_list args;
va_start (args, format);
fprintf(file, "%s: ", getTimestamp());
vfprintf (file, format, args); // 在这个地方用vfprintf函数就很合适,因为
// 第三个参数可以直接得到
va_end (args);
}
vfprintf适合参数可变列表传递。
sprintf: 第一个参数是字符串缓冲区,后面是一个格式字串。sprintf不是将格式化结果标准输出,而是将其存入szBuffer。该函数返回该字符串的长度。
vsprintf:vsprintf 是sprintf 的一个变形,它有三个参数。vsprintf 用于执行有不定数量参数的函数。vsprintf的前两个参数与sprintf相同:一个用于保存结果的字符串缓冲区和一个格式化字符串。第三个参数是指向格式化参数队列的指针。实际上,该指针指向在堆栈中供函数调用的变量。va_list、va_start和va_end宏(在STDARG.H中定义)帮助我们处理堆栈指针。
int sprintf (char * szBuffer, const char * szFormat, ...)
{
int iReturn ;
va_list pArgs ;
va_start (pArgs, szFormat) ;
iReturn = vsprintf (szBuffer, szFormat, pArgs) ;
va_end (pArgs) ;
return iReturn ;
}
va_start宏将pArg设置为指向一个堆栈变量,该变量位址在堆栈参数szFormat的上面。
snprintf:
vsnprintf:
将n字节写入str所指向的内存,n的大小包含'\0';
如果要写入的字符串的长度大于或者等于n,则源字符串被截断,并且不会向目的内存写入'\0';
函数的返回值为实际写入字节数的大小,所以如果函数返回值大于或者等于n,则证明源字符串被截断;
int snprintf(char *s, int size, const char *fmt, ...)
{
va_list ap;
int n=0;
va_start(ap, fmt); //获得可变参数列表
n=vsnprintf (s, size, fmt, ap); //写入字符串s
va_end(ap); //释放资源
return n; //返回写入的字符个数
}
---------------------------------------
关于 % 格式的介绍:
基本格式 含义
%d 整型十进制
%u 无符号整型(对于八进制,十六进制来说没有符号区别)
%o 八进制
%x/%X 小写/大写的十六进制
%c 字符
%s 字符串
%f 浮点数,不使用科学表示法
%g/%G 六位有效数字表示法,当太大或太小时自动使用科学表示法
%e/%E 科学表示法,六位有效数字
标志 含义
‘-’ 左对齐
‘+’ 输出正负号,当然是对于十进制数来说的
‘ ’ 和‘+’类似,但是正数
可变域宽和精度
当想要打印出指定宽度的数字或字符串时,就可以指定域宽,使用宽度和精度修饰符“*”。
printf("%*.*s/n",14,14,name); //打印14个字符
printf("%*.*s/n",14,5,name); //只打印出5个字符(前面补空格)
#define NAMESIZE 14
char name[NAMESIZE];
printf("%NAMESIZEs/n",name);
但是:上面的语法有错误,编译的时候会提示错误的类型 %N,因为宏由预编译来处理,而预编译不会进入到字符串内部! |