1. stdio.h — 标准输入输出
提供标准输入输出操作,按功能分组说明。
头文件说明:本章按功能分组,下面几节的内容不在
<stdio.h>中,使用时需要包含<wchar.h>:
- 1.3、1.4、1.7 中的宽字符函数(
wprintf族、wscanf族、fgetwc/fputwc等)以及fwide。文件 I/O:本库实现了
fopen/fclose/remove,但裸机上没有文件系统,运行时这些调用会失败;rename没有实现,使用它会导致链接失败(见 10.2 G3)。
1.1 格式化输出
int printf(const char *fmt, ...)
格式化输出到 stdout。
- 输入: fmt 格式字符串, ... 可变参数
- 输出: int 输出字符数,负值表示错误
int fprintf(FILE *fp, const char *fmt, ...)
格式化输出到文件。
- 输入: fp 文件指针, fmt 格式串, ... 参数
- 输出: int 输出字符数
int sprintf(char *buf, const char *fmt, ...)
格式化输出到字符串。
- 输入: buf 缓冲区, fmt 格式串, ... 参数
- 输出: int 输出字符数
- 注意: 不检查缓冲区溢出,已弃用,改用 snprintf
int snprintf(char *buf, size_t n, const char *fmt, ...)
安全格式化到字符串。
- 输入: buf 缓冲区, n 最大字节数, fmt 格式串, ... 参数
- 输出: int 应写入字符数(不含\0),超过 n 时被截断
int vprintf(const char *fmt, va_list ap)
printf 的 va_list 版本。
- 输入: fmt 格式串, ap 参数列表
- 输出: int 输出字符数
int vfprintf(FILE *fp, const char *fmt, va_list ap)
fprintf 的 va_list 版本。
- 输入: fp 文件指针, fmt 格式串, ap 参数列表
- 输出: int 输出字符数
int vsprintf(char *buf, const char *fmt, va_list ap)
sprintf 的 va_list 版本。
- 输入: buf 缓冲区, fmt 格式串, ap 参数列表
- 输出: int 输出字符数
int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap)
snprintf 的 va_list 版本。
- 输入: buf 缓冲区, n 大小, fmt 格式串, ap 参数列表
- 输出: int 应写入字符数
1.2 格式化输入
int scanf(const char *fmt, ...)
从 stdin 格式化输入。
- 输入: fmt 格式字符串, ... 参数(取地址)
- 输出: int 成功匹配项数,EOF 表示失败
int fscanf(FILE *fp, const char *fmt, ...)
从文件格式化输入。
- 输入: fp 文件指针, fmt 格式串, ... 参数
- 输出: int 成功匹配项数
int sscanf(const char *str, const char *fmt, ...)
从字符串格式化输入。
- 输入: str 字符串, fmt 格式串, ... 参数
- 输出: int 成功匹配项数
int vscanf(const char *fmt, va_list ap)
scanf 的 va_list 版本。
- 输入: fmt 格式串, ap 参数列表
- 输出: int 成功匹配项数
int vfscanf(FILE *fp, const char *fmt, va_list ap)
fscanf 的 va_list 版本。
- 输入: fp 文件指针, fmt 格式串, ap 参数列表
- 输出: int 成功匹配项数
int vsscanf(const char *str, const char *fmt, va_list ap)
sscanf 的 va_list 版本。
- 输入: str 字符串, fmt 格式串, ap 参数列表
- 输出: int 成功匹配项数
1.3 宽字符格式化输出
int wprintf(const wchar_t *fmt, ...)
宽字符格式化输出到 stdout。
- 输入: fmt 宽格式串, ... 参数
- 输出: int 输出字符数
int fwprintf(FILE *fp, const wchar_t *fmt, ...)
宽字符格式化输出到文件。
- 输入: fp 文件指针, fmt 宽格式串, ... 参数
- 输出: int 输出字符数
int swprintf(wchar_t *buf, size_t n, const wchar_t *fmt, ...)
宽字符格式化到字符串。
- 输入: buf 宽缓冲区, n 大小, fmt 宽格式串, ... 参数
- 输出: int 应写入字符数
int vwprintf(const wchar_t *fmt, va_list ap)
wprintf 的 va_list 版本。
- 输入: fmt 宽格式串, ap 参数列表
- 输出: int 输出字符数
int vfwprintf(FILE *fp, const wchar_t *fmt, va_list ap)
fwprintf 的 va_list 版本。
- 输入: fp 文件指针, fmt 宽格式串, ap 参数列表
- 输出: int 输出字符数
int vswprintf(wchar_t *buf, size_t n, const wchar_t *fmt, va_list ap)
swprintf 的 va_list 版本。
- 输入: buf 宽缓冲区, n 大小, fmt 宽格式串, ap 参数列表
- 输出: int 应写入字符数
1.4 宽字符格式化输入
int wscanf(const wchar_t *fmt, ...)
从 stdin 宽字符格式化输入。
- 输入: fmt 宽格式串, ... 参数
- 输出: int 成功匹配项数
int fwscanf(FILE *fp, const wchar_t *fmt, ...)
从文件宽字符格式化输入。
- 输入: fp 文件指针, fmt 宽格式串, ... 参数
- 输出: int 成功匹配项数
int swscanf(const wchar_t *str, const wchar_t *fmt, ...)
从宽字符串格式化输入。
- 输入: str 宽字符串, fmt 宽格式串, ... 参数
- 输出: int 成功匹配项数
int vwscanf(const wchar_t *fmt, va_list ap)
wscanf 的 va_list 版本。
- 输入: fmt 宽格式串, ap 参数列表
- 输出: int 成功匹配项数
int vfwscanf(FILE *fp, const wchar_t *fmt, va_list ap)
fwscanf 的 va_list 版本。
- 输入: fp 文件指针, fmt 宽格式串, ap 参数列表
- 输出: int 成功匹配项数
int vswscanf(const wchar_t *str, const wchar_t *fmt, va_list ap)
swscanf 的 va_list 版本。
- 输入: str 宽字符串, fmt 宽格式串, ap 参数列表
- 输出: int 成功匹配项数
1.5 字符 I/O
int fgetc(FILE *fp)
从文件读取一个字符。
- 输入: fp 文件指针
- 输出: int 读取的字符(转为 unsigned char)或 EOF
int getc(FILE *fp)
fgetc 的宏版本。
- 输入: fp 文件指针
- 输出: int 读取的字符或 EOF
- 注意: 可能多次求值 fp,避免传入含副作用的表达式
int getchar(void)
从 stdin 读取一个字符。
- 输入: 无
- 输出: int 读取的字符或 EOF
char* fgets(char *s, int n, FILE *fp)
从文件读取一行。
- 输入: s 缓冲区, n 最大读取字符数, fp 文件指针
- 输出: char* s 或 NULL(EOF/错误)
- 注意: 保留换行符,最多读 n-1 字符,末尾补 \0
char* gets(char *s)
从 stdin 读取一行。
- 输入: s 缓冲区
- 输出: char* s 或 NULL
- 注意: 不检查缓冲区溢出,C11 已移除,极度危险
int fputc(int c, FILE *fp)
向文件写入一个字符。
- 输入: c 字符, fp 文件指针
- 输出: int 写入的字符或 EOF
int putc(int c, FILE *fp)
fputc 的宏版本。
- 输入: c 字符, fp 文件指针
- 输出: int 写入的字符或 EOF
int putchar(int c)
向 stdout 写入一个字符。
- 输入: c 字符
- 输出: int 写入的字符或 EOF
int fputs(const char *s, FILE *fp)
向文件写入字符串(不含换行)
- 输入: s 字符串, fp 文件指针
- 输出: int 非负成功,EOF 失败
int puts(const char *s)
向 stdout 写入字符串(自动加换行)
- 输入: s 字符串
- 输出: int 非负成功,EOF 失败
int ungetc(int c, FILE *fp) | 【C90 §7.19.7.11】
将一个字符放回输入流。
- 输入: c 字符(须为
unsigned char可表示值或EOF),fp 文件指针 - 输出: int 成功时返回放回的字符,失败返回
EOF - 注意: 至少保证可回推 1 个字符;会清除该流的 EOF 标志。
1.6 二进制 I/O
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
从文件读取二进制数据。
- 输入: ptr 缓冲区, size 元素大小, nmemb 元素数, fp 文件指针
- 输出: size_t 实际读取元素数
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
向文件写入二进制数据。
- 输入: ptr 缓冲区, size 元素大小, nmemb 元素数, fp 文件指针
- 输出: size_t 实际写入元素数
1.7 宽字符 I/O
注意:本节偏差:① 宽字符流在交付配置下把
wchar_t的 4 字节原始表示直灌流,并非标准要求的多字节编码(G4);②fwide没有"未定向"状态、对已定向流仍会改向,fgetwc到流尾不置 EOF 标志(G5)。详见 10.2、10.7.1 L9 / L10。
wint_t fgetwc(FILE *fp)
从文件读取一个宽字符。
- 输入: fp 文件指针
- 输出: wint_t 宽字符或 WEOF
- 注意:行为偏差(G5): 读到流尾返回
WEOF,但不置 EOF 标志——feof(fp)恒为 0。判断宽字符输入结束须直接比较返回值== WEOF。详见 10.2 G5 / 10.7.1 L10。
wint_t getwchar(void)
从 stdin 读取一个宽字符。
- 输入: 无
- 输出: wint_t 宽字符或 WEOF
wchar_t* fgetws(wchar_t *s, int n, FILE *fp)
从文件读取宽字符行。
- 输入: s 宽缓冲区, n 大小, fp 文件指针
- 输出: wchar_t* s 或 NULL
wint_t fputwc(wchar_t c, FILE *fp)
向文件写入一个宽字符。
- 输入: c 宽字符, fp 文件指针
- 输出: wint_t 宽字符或 WEOF
wint_t putwchar(wchar_t c)
向 stdout 写入一个宽字符。
- 输入: c 宽字符
- 输出: wint_t 宽字符或 WEOF
int fputws(const wchar_t *s, FILE *fp)
向文件写入宽字符串。
- 输入: s 宽字符串, fp 文件指针
- 输出: int 非负成功,EOF 失败
wint_t ungetwc(wint_t c, FILE *fp)
将宽字符放回输入流。
- 输入: c 宽字符, fp 文件指针
- 输出: wint_t 放回的宽字符或 WEOF
int fwide(FILE *fp, int mode)
设置/查询流定向。
- 输入: fp 文件指针, mode 模式(正=宽字符, 负=字节, 0=仅查询)
- 输出: int 正=宽字符, 负=字节, 0=未定向
- 注意:行为偏差(G5): 本库没有"未定向"状态——流初始即视为字节定向,故未定向流上
fwide(fp, 0)返回 -1 而非 0;且对已定向流调用fwide(fp, ±1)会改变其定向(标准要求保持不变)。不要用fwide判断流是否已定向,也不要依赖它维持定向。详见 10.2 G5 / 10.7.1 L10。
wint_t getwc(FILE *fp) | 【C99 §7.24.3.1】
从文件读取一个宽字符(fgetwc 的宏版本)。实际头:<wchar.h>。
- 输入: fp 文件指针
- 输出: wint_t 宽字符或
WEOF - 注意: 实现为
fgetwc的强别名。
wint_t putwc(wchar_t c, FILE *fp) | 【C99 §7.24.3.3】
向文件写入一个宽字符(fputwc 的宏版本)。实际头:<wchar.h>。
- 输入: c 宽字符, fp 文件指针
- 输出: wint_t 宽字符或
WEOF - 注意: 实现为
fputwc的强别名。
1.8 文件定位
int fseek(FILE *fp, long offset, int whence)
设置文件位置。
- 输入: fp 文件指针, offset 偏移量, whence 起始位置(SEEK_SET/SEEK_CUR/SEEK_END)
- 输出: int 0 成功,非零失败
long ftell(FILE *fp)
获取当前文件位置。
- 输入: fp 文件指针
- 输出: long 当前位置,-1L 表示错误
void rewind(FILE *fp)
重置文件位置到开头。
- 输入: fp 文件指针
- 输出: 无
- 注意: 同时清除错误标志和 EOF 标志
int fgetpos(FILE *fp, fpos_t *pos)
获取当前文件位置。
- 输入: fp 文件指针, pos 位置指针
- 输出: int 0 成功,非零失败
int fsetpos(FILE *fp, const fpos_t *pos)
设置文件位置。
- 输入: fp 文件指针, pos 位置指针
- 输出: int 0 成功,非零失败
1.9 缓冲控制
int fflush(FILE *fp)
刷新输出缓冲区。
- 输入: fp 文件指针(或 NULL 刷新所有输出流)
- 输出: int 0 成功,EOF 失败
void setbuf(FILE *fp, char *buf)
设置缓冲区。
- 输入: fp 文件指针, buf 缓冲区(为 NULL 则关闭缓冲)
- 输出: 无
- 注意: 等价于 setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ)
int setvbuf(FILE *fp, char *buf, int mode, size_t size)
设置缓冲区模式。
- 输入: fp 文件指针, buf 缓冲区, mode 模式, size 大小
- 输出: int 0 成功,非零失败
- 注意: mode 为 _IOFBF(全缓冲)/_IOLBF(行缓冲)/_IONBF(无缓冲)
1.10 错误与状态
int feof(FILE *fp)
检查文件结束标志。
- 输入: fp 文件指针
- 输出: int 非零表示已到 EOF
int ferror(FILE *fp)
检查错误标志。
- 输入: fp 文件指针
- 输出: int 非零表示有错误
void clearerr(FILE *fp)
清除文件错误和 EOF 标志。
- 输入: fp 文件指针
- 输出: 无
void perror(const char *s)
输出错误信息。
- 输入: s 前缀字符串(可为 NULL)
- 输出: 无
- 注意: 输出格式为 "s: 错误描述\n"
1.11 文件操作
注意:可用性说明 —— 本节的函数在交付库中均可正常链接,但交付配置无文件系统:底层
open/unlink落到nosys桩,故fopen/freopen/tmpfile/remove等在运行时返回失败。唯一例外是rename:本库无实现,使用会导致链接失败(见 10.2 G3)。
FILE* fopen(const char *path, const char *mode)
打开文件。
- 输入: path 文件路径, mode 打开模式("r"/"w"/"a" 等)
- 输出: FILE* 文件指针,失败返回 NULL
- 注意: mode 决定读写权限,如 "r+" 表示读写
int fclose(FILE *fp)
关闭文件。
- 输入: fp 文件指针
- 输出: int 0 成功,EOF 失败
FILE* freopen(const char *path, const char *mode, FILE *fp)
重定向流。
- 输入: path 路径, mode 模式, fp 旧文件指针
- 输出: FILE* 新文件指针,失败返回 NULL
int remove(const char *path)
删除文件。
- 输入: path 文件路径
- 输出: int 0 成功,非零失败
注意:
rename本库未提供 —— 标准函数int rename(const char *old, const char *new)(C90 §7.9.4.2 / C99 §7.19.4.2)在交付库中无实现,使用它会导致链接失败(undefined symbol: rename)。详见 10.2 G3。
FILE* tmpfile(void)
创建临时文件。
- 输入: 无
- 输出: FILE* 临时文件指针,失败返回 NULL
- 注意: 文件在关闭或程序结束时自动删除
char* tmpnam(char *s)
生成临时文件名。
- 输入: s 缓冲区(可为 NULL,使用内部静态缓冲区)
- 输出: char* 临时文件名
- 注意: 建议改用 tmpfile