Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1814332
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-03-29 12:06:22

格式化输出

格式化输出由4个printf函数处理



  1. #include <stdio.h>

  2. int printf(const char *restrict format, ...);

  3. int fprintf(FILE *restrict fp, const char *restrict format, ...);

  4. 两者成功都返回字符数,输出错误则返回负值。

  5. int sprintf(char *restrict buf, const char *restrict format, ...);

  6. int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);

  7. 两者成功都返回在字节里存储的字符数量,编码错误返回负值。


printf函数向标准输出写,fprintf向一个指定的流写,而sprintf把格式化的字符串放入到数组buf里。sprintf函数在数组末自动将上一个空字节,但这个空字节没有包含在返回值里。


注意sprintf可能为溢出buf指向的缓冲区。这是调用者的执行来保证这个缓冲区足够大。因为这会导致缓冲区溢出的问题,于是snprintf被引 入。用它可以把缓冲的尺寸作为一个显式的参数;任何超过缓冲区末尾的字符都会被舍弃掉。snprintf函数返回假如缓冲足够大时会写入的字符数。而 sprintf一样,返回值不包括终止的空字节。如果snprintf返回一个比缓冲大小n更小的正值,那么输出则被裁切过了。如果编码出 错,snprintf返回一个负值。


格式规范控制了剩下的参数如何被编码和最终显示。每个参数根据一个以百分号(%)开头的转换规格(conversion specification)来编码。除了转换规格,其它在格式里的字符都被无修改地复制。一个转换规格有4个可先部分,如下方括号里所示:


%[flags] [fldwidth] [precision] [lenmodifier] convtype


flags由下表汇总:

转换规格的flag部分
Flag 描述
- 域里面左输出
+ 总是显示一个正负号
(空格) 如果没有正负号则以一个空格开头
# 使用代替的格式转换(例如16进制格式中包含0x前缀)
0 以0填充,而不是空格

fldwidth部分指定了最小的域宽度。如果转换结果有更少的字符,则以空格填充。域完是一个非负十进制整数或一个星号。


precision部分在整数转换时指定了整数中数字的最小数量,在浮点数转换时指定了小数点右侧的数字的最小数量,或者在字符串转换中指定字节的最大数量。precision是一个“.”接着一个可选的非负十进制整数或星号。


域宽和精度都可以是一个星号。这种情况下,一个指定这个值的参数被使用,它直接在出现在被转换的参数前。


lenmodifier部分指定了参数的尺寸。下表总结了可能的值:

转换格式的长度修改符
Length modifier 描述
hh 有符号或无符号char
h 有符号或无符号short
l 有符号或无符号long或宽字符
ll 有符号或无符号long long
j intmax_t或uintmax_t
z size_t
t ptrdiff_t
L long double


convtype部分不是可选的。它控制了参数如何被解释。下表总结了各种转换类型:

转换规格的转换类型部分
Conversion type 描述
d, i 有符号十进制
o 无符号八进制
u 无符号十进制
x, X 无符号十六进制
f, F double浮点数
e, E 指数格式的double浮点数
g, G 根据要转换的值,以f,F,e或E来解释
a, A 十六进制指数格式的double浮点数
c 字符(长度修改符l表示宽字符)
s 字符串(长度修改符l表示宽字符串)
p void指针
n 指向表示目前为止已写字符数量的有符号整型的指针
% 一个%字符
C 宽字符(XSI扩展,等价于lc)
S 宽字符串(XIS扩展,等价于ls)


下面4个printf家族的变体与前4个函数相似,只是参数列表(...)被arg代替。



  1. #include <stdarg.h>
  2. #include <stdio.h>

  3. int vprintf(const char *restrict format, va_list arg);

  4. int vfprintf(FILE *restrict fp, const char *restrict format, va_list arg);

  5. 两者成功都返回输出的字符数,失败返回负值

  6. int vsprintf(char *restrict buf, const char *restrict format, va_list arg);

  7. int vsnprintf(char *restrict buf, size_t n, const char *restrict format, va_list arg);

  8. 两都成功都返回数组存储的字符数,编码错误返回负数。


注意可变长度的参数列表由ISO C提供,定义在头文件以及相关的程序,与老的UNIX系统提供在程序的不同。


格式化输入

格式化输入由三个scanf函数处理



  1. #include <stdio.h>

  2. int scanf(const char *restrict format, ...);

  3. int fscanf(FILE *restrict fp, const char *restrict format, ...);

  4. int sscanf(const char *restrict buf, const char *restrict format, ...);

  5. 三者都返回被赋值的输入项的数目,输入出错或碰到文件结尾时返回EOF。


scanf家族用来解析一个输入的字符串并转换成指定类型的变量。在格式后的参数包含需要用转换结果初绐化的变量的地址。


格式规格(format specification)控制了参数如何为赋值而被转换。百分号(%)表示格式规格的开始。除了转换规格和空格,其它在格式里的字符都用来匹配输入。如果有一个字符不匹配,操作停止,不再读剩下的输入。


转换规格中有三个可选部分,如下面方括号里所示:
%[*] [fldwidth] [lenmodifier] convtype


可选的开头的星号用来抑制转换。输入根据转换规格的其它部分转换,但结果不会存储在一个参数里。


fldwidth部分指定域的最大字符数。lenmodifier部分指定要以转换结果初始化的参数的尺寸。被printf家族支持的长度修改符同样也被scanf家族支持。


convtype域与printf家族所用的转换类型域类似,但有一些不同。一个区别是,存在一个无符号类型的结果在输入里可以是有符号的。下表总结了scanf家族支持的转换类型:

转换规格的转换类型部分
Conversion type 描述
d 有符号十进制
i 有符号数,根据输入格式决定进制
o 无符号八进制(输入可以是有符号的)
u 无符号十进制(输入可以是有符号的)
x 无符号十六进制(输入可以是有符号的)
a, A, e, E, f, F, g, G 浮点数
c 字符(长度修改符l表示宽字符)
s 字符串(长度修改符l表示宽字符串)
[ 匹配一个字符列表,以]结束
[^ 匹配除列出的之外的所有字符,以]结束
p void指针
n 指向表示目前为止已写字符数量的有符号整型的指针
% 一个%字符
C 宽字符(XSI扩展,等价于lc)
S 宽字符串(XIS扩展,等价于ls)


和printf家族一样,scanf家族也支持使用可变参数列表的函数,它们由指定。



  1. #include <stdarg.h>
  2. #include <stdio.h>

  3. int vscanf(const char *restrict format, va_list arg);

  4. int vfscanf(FILE *restrict fp, const char *restrict format, va_list arg);

  5. int vsscanf(const char *restrict buf, const char *restrict format, va_list arg);

  6. 三者都返回赋好值的输入项的数量,错误或转换前遇到文件结尾时返回EOF。


参考你的UNIX系统手册来获得更多关于scanf家族函数的细节。

阅读(853) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~