名称
scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf – 格式化输入转换
概要
#include
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
#include
int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);
对于glibc来说要有功能测试宏才能使用(参考feature_test_macros):
vscanf(), vsscanf(), vfscanf():
_XOPEN_SOURCE >= 600 || _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L;
or cc -std=c99
说明
scanf函数族按照下文描述的格式扫描输入。格式可以包含多个转换规则。转换的
结果,如果有的话,存储在格式之后的指针参数所指向的位置。每个指针参数的类
型必须与转换之后的结果的类型匹配。
如果格式中的转换规则的数量超过了指针参数的数量,那么结果是未定义的。如果
指针参数的数量超过了转换规则的数量,那么超过的指针参数会被计算但是不会做
其他操作。
scanf从标准输入流stdin读取输入,fscanf从stream指向的流读取输入,sscanf从
str指向的字符串读取输入。
vfscanf类似于vfprintf,使用可变的指针参数列表从stream指向的流读取输入(参
考stdarg)。vscanf从标准输入扫描可变参数列表,vsscanf从字符串扫描可变参数
列表,它们分别类似于vprintf和vsprintf。
格式串由一系列指令组成,这些指令描述了如何处理输入的字节序列。当一条指令
执行失败时就不会继续读取输入,函数返回。下列情况会导致失败:输入失败,即
输入字符不可用,或者匹配失败,意味着输入不合适(看下述说明)。
下列的描述都是指令:
· 一系列空白字符(空格,制表符,换行符等,参考isspace)。该指令匹
配输入中任意数量的空白字符,包括零个。
· 普通字符(既不是空白字符也不是’%’)。此字符必须与输入的下一个字
符完全匹配。
· 转换规则,以一个’%’(百分号)开头。输入中的字符序列根据此规则进
行转换,并将结果放在相应的指针参数中。如果输入项与规则不匹配,
那么转换失败,这是一个匹配失败。
每条转换规则要么以字符’%’开头,或者以字符序列"%n$"开头(区别见下文),后
面跟着如下内容:
· 一个可选的赋值抑制字符’*’:scanf按照转换规则读取输入,但丢弃读到
的内容。不需要相应的指针参数,并且此规则不包含在scanf成功时返回
的计数中。
· 一个可选的字符’m’。用于字符串的转换(%s,%c,%[),调用者无需分
配相应的缓冲区来保存输入,相反,scanf分配一个足够大小的缓冲区,
并将该缓冲区的地址分配给相应的指针参数,该指针参数指向char *类型
的变量(这个变量不需要在调用前初始化),调用者应该在不需要该缓冲
区时释放它。
· 一个可选的十进制整数,用于指定最大字段宽度。当达到此最大值或找
到不匹配的字符时(以先发生者为准)停止读取字符。大多数转换会丢
弃开头的空白字符(下文会描述例外的情况),并且这些丢弃的字符不
计入最大字段宽度。字符串输入转换存储一个结束符('\0')来标记输入
的结束,最大字段宽度不包括该字符。
· 一个可选的类型修饰符。例如,l修饰符与整数转换如%d一起使用,表
示对应的指针参数指向一个long int类型而不是int类型。
· 转换说明符,用来指定输入转换的类型。
转换规则有两种形式,要么以'%'开始,要么以"%n$"开始。两种形式不应混合在同
一个格式串中,除了包含"%n$"规则的格式串可以包含%%和%*之外。如果格式包
含’%’规则,那么它们与指针参数按序一一对应。在"%n$"形式(在 POSIX.1-2001 中
指定,但在 C99 中未指定)中,n是一个十进制整数,指定转换后的输入应放置
在第n个指针参数所指的位置。
转换
以下类型修饰符可以出现在转换规则中:
h 指示转换将是d、i、o、u、x、X或n之一,并且指针指向short int或unsigned
short int(而不是 int)。
hh 跟h一样,但是指针指向signed char或者unsigned char。
j 跟h一样,但是指针指向intmax_t或者uintmax_t。该修饰符由C99引进。
l 指示转换将是d、i、o、u、x、X或n之一,并且指针指向long int或unsigned
long int(而不是 int),或者转换将是e、f或g,并且指针指向double(而
不是float)。两个l字符相当于L。如果与%c或%s一起使用,则相应的参
数被视为分别指向宽字符或宽字符串的指针。
L 指示转换将是e、f或g之一,并且指针指向long double,或者转换将是d、
i、o、u或x,并且指针指向long long。
q 等于L。该说明符在ANSI C中不存在。
t 跟h一样,但是指针指向ptrdiff_t。该修饰符由C99引进。
z 跟h一样,但是指针指向size_t。该修饰符由C99引进。
有下列转换说明符可用:
% 匹配字符’%’,即格式串中的%%匹配输入的单个'%'字符,没有做转换(但
是前面的空白字符被丢弃),也不会赋值。
d 匹配一个有符号十进制整数,指针必须指向int类型。
D 相当于ld,只是为了向后兼容。(注意:只在libc4中支持,libc5和glibc
默认忽略%D,因而引起旧程序莫名地失败。)
i 匹配一个有符号整数,指针必须指向int类型。如果整数以0x或0X开头,
则以16进制读取,如果以0开头,则以8进制读取,其他情况按照10进
制读取。字符需要与基数的范围对应。
o 匹配一个无符号8进制整数,指针必须指向unsigned int类型。
u 匹配一个无符号10进制整数,指针必须指向unsigned int类型。
x 匹配一个无符号16进制整数,指针必须指向unsigned int类型。
X 相当于x。
f 匹配一个有符号浮点数,指针必须指向float类型。
e 相当于f。
g 相当于f。
E 相当于f。
a (在C99)相当于f。
s 匹配一串非空白字符序列,指针必须指向字符数组的初始元素,数组长度
足以容纳输入序列和结束符('\0'),其中结束符是自动添加的。输入字符串
在空白处或最大字段宽度处停止,以先发生者为准。
c 匹配一串字符序列,其长度由最大字段宽度(默认为 1)指定,指针必须
指向char类型,并且必须有足够的空间容纳所有的字符(不会添加结束符)。
不会跳过前面的空格,如果想先跳过空格,那么需要在格式串中显式地加
一个空格。
[ 匹配接收字符中的非空字符串,指针必须指向char类型,并且必须有足够
的空间容纳串中的所有字符,包括结束符,不会跳过前面的空格,串由属
于(或者不属于)特定字符集的字符组成,字符集由左括号’[‘和右括号’]’
之间的字符组成,如果’[‘后的第一个字符为’^’则表示字符集由不包含’[‘和’]’
之间的字符组成。为了在字符中包含’]‘,必须将该字符放在’[‘或者’^’后面
的第一个字符位置处,放在其他任何位置都表示为字符集定义结束。连字
符’-’也比较特殊,当把它放在两个字符的中间时,表示所有它们中间的字
符也添加进字符集中。为了在字符中包含’-‘,必须将它作为最后一个字符
放在’]’的前面。例如,[^]0-9-]表示为除了右括号’]‘、零到九和连字符之外
的所有内容。当出现字符集以外的字符或者超过最大字段宽度时匹配结束。
p 匹配一个指针值(就好像在printf中使用%p一样),指针必须指向void *
类型。
n 没有什么是预期的。到目前为止从输入消耗的字符数通过下一个指针存储,
该指针必须是指向int的指针。这不是转换并且不会增加函数返回的计数
值。可以使用字符’*’来抑制赋值,但对返回值的影响是不确定的,因此不
应使用%*n转换。
返回值
成功时,这些函数返回成功匹配和赋值的项数,在匹配失败的情况下,这可能比预
期的项数要少,甚至为零。
如果在第一次成功转换之前或匹配失败之前到达输入末尾,则返回EOF。如果出现
读错误,也会返回EOF,在这种情况下会设置流的错误标志,errno对应此时的错
误。
错误码
EAGAIN 与流关联的文件描述符被标记为非阻塞,而读操作会引起阻塞。
EBADF 与流关联的文件描述符非法,或者没有以读方式打开文件。
EILSEQ 输入的字节序列没有组成有效字符。
EINTR 读操作被信号中断。
EINVAL 没有足够的参数,或者格式串format为NULL。
ENOMEM 内存不足。
ERANGE 整数转换的结果超过相应整数类型可以存储的大小。
线程安全特征
接口 |
特征 |
值 |
scanf(), fscanf(), sscanf(), vscanf(),vsscanf(), vfscanf() |
线程安全 |
locale级别多线程安全 |
标准
函数fscanf(), scanf(), sscanf()遵循C89、C99和POSIX.1-2001,这些标准没有指定
ERANGE错误码。
修饰符q在4.4BSD用于long long类型,而ll或者L在GNU中用于整数转换。
这些函数的Linux版本基于GNU libio库,可以查看GNU libc(glibc-1.08)的信息文
档以获得更简洁的描述。
注意
'a' 赋值分配修饰符
最初,GNU C库支持通过'a'字符动态分配字符串输入(作为非标准扩展)。(这
个特性至少可以追溯到 glibc 2.0。)因此,可以编写以下内容让scanf()为输入字
符串分配一个缓冲区,并在*buf中返回指向该缓冲区的指针。
char *buf;
scanf("%as", &buf);
这样使用字符’a’是有问题的,因为’a’也被ISO C标准指定为f(浮点输入)的同义词。
POSIX.1-2008改为用m修饰符赋值。(如上文所述)。
请注意,如果使用gcc -std=c99或gcc -D_ISOC99_SOURCE编译程序,则a修饰符不
可用(除非同时指定了_GNU_SOURCE),此时a被解释为浮点数的说明符(见上
文)。
从 2.7 版开始,glibc中添加了对m修饰符的支持,新程序应使用该修饰符而不是
a。
除了被POSIX标准化之外,m修饰符相比于a还有以下优点:
* 它也可以应用于%c转换说明符(例如%3mc)。
* 它避免了关于%a浮点转换说明符的歧义(并且不受gcc -std=c99等的影响)。
BUGS
所有函数完全遵循C89,但提供附加说明符q和a以及L和l说明符的附加行为。
这些附加的功能可能被认为是一个错误,因为它改变了C89中定义的说明符的行
为。
ANSI C定义的类型修饰符和转换说明符的某些组合没有意义(例如%Ld)。虽然它
们在Linux上可能有明确定义的行为,但在其他架构上不一定如此。因此,通常最
好使用ANSI C根本没有定义的修饰符,即使用q或ll而不是L与d、i、o、u、x、
X转换结合使用。
q的用法与4.4BSD上的不同,因为它和L等效地用于浮点转换。
示例
要使用动态分配转换说明符,请将m指定为长度修饰符(因此为%ms或%m[range])。
调用者释放返回的字符串,如下例所示:
char *p;
int n;
errno = 0;
n = scanf("%m[a-z]", &p);
if (n == 1) {
printf("read: %s\n", p);
free(p);
} else if (errno != 0) {
perror("scanf");
} else {
fprintf(stderr, "No matching characters\n");
}
如上例所示,只有在scanf成功读取字符串时才需要调用free。
推荐阅读
getc,printf,setlocale,strtod,strtol,strtoul
版本记录
这个页面是Linux man-pages项目4.04版本的一部分。关于该项目的信息和bug报
道可以在该网站找到:http://www.kernel.org/doc/man-pages/。
2015-04-19