> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/stdio/scanf.3.md).

# scanf(3)

`scanf` — 输入格式转换

## 名称

`scanf`, `fscanf`, `sscanf`, `vscanf`, `vsscanf`, `vfscanf`

## 库

Lb libc

## 概要

`#include <stdio.h>`

`Ft int Fn scanf const char * restrict format ... Ft int Fn fscanf FILE * restrict stream const char * restrict format ... Ft int Fn sscanf const char * restrict str const char * restrict format ...`

`#include <stdarg.h>`

`Ft int Fn vscanf const char * restrict format va_list ap Ft int Fn vsscanf const char * restrict str const char * restrict format va_list ap Ft int Fn vfscanf FILE * restrict stream const char * restrict format va_list ap`

## 描述

`scanf` 函数族根据如下所述的 `format` 扫描输入。该格式中可包含*转换说明符；转换的结果（若有）通过指针*参数存储。`scanf` 函数从标准输入流 `stdin` 读取输入，`fscanf` 从流指针 `stream` 读取输入，`sscanf` 从 `str` 所指向的字符串读取输入。`vfscanf` 类似于 vfprintf(3)，使用指针的可变参数列表从流指针 `stream` 读取输入（参见 [stdarg(3)](/misc/stdarg.3.md)）。`vscanf` 从标准输入扫描可变参数列表，`vsscanf` 从字符串扫描；二者分别类似于 `vprintf` 和 `vsprintf` 函数。每个后续的*指针*参数必须与每个后续的转换说明符正确对应（但参见下文的 `*` 转换）。所有转换均以 `%`（百分号）字符引入。`format` 字符串中也可包含其他字符。`format` 字符串中的空白字符（如空格、制表符或换行符）匹配输入中任意数量的空白字符，包括零个。其他字符仅匹配其自身。当输入字符不匹配此类格式字符时，扫描停止。当无法进行输入转换时（参见下文），扫描也会停止。

## 转换

在引入转换的 `%` 字符之后，可跟随若干*标志*字符，如下所示：

**`*`** 抑制赋值。随后的转换照常进行，但不使用指针；转换结果直接被丢弃。

**`hh`** 表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `char` 的指针（而非 `int`）。

**`h`** 表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `short int` 的指针（而非 `int`）。

**`l`**（ell）表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `long int` 的指针（而非 `int`）；或转换将为 `a`、`e`、`f` 或 `g` 之一，且下一个指针是指向 `double` 的指针（而非 `float`）；或转换将为 `c`、`s` 或 `[` 之一，且下一个指针是指向 `wchar_t` 数组的指针（而非 `char`）。

**`ll`**（ell ell）表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `long long int` 的指针（而非 `int`）。

**`L`** 表示转换将为 `a`、`e`、`f` 或 `g` 之一，且下一个指针是指向 `long double` 的指针。

**`j`** 表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `intmax_t` 的指针（而非 `int`）。

**`t`** 表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `ptrdiff_t` 的指针（而非 `int`）。

**`w`** `N`（其中 `N` 为 8、16、32 或 64）表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `intN_t` 的指针（而非 `int`）。

**`wf`** `N`（其中 `N` 为 8、16、32 或 64）表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `int_fastN_t` 的指针（而非 `int`）。

**`z`** 表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `size_t` 的指针（而非 `int`）。

**`q`**（已弃用）表示转换将为 `bdioux` 或 `n` 之一，且下一个指针是指向 `long long int` 的指针（而非 `int`）。

除这些标志外，在 `%` 和转换之间还可有一个可选的最大字段宽度，以十进制整数表示。若未指定宽度，则默认为“无穷大”（但下文有一个例外）；否则在处理转换时最多扫描该数量的字节。对于 `lc`、`ls` 和 `l[` 转换，字段宽度指定扫描的最大多字节字符数。在转换开始前，大多数转换会跳过空白字符；该空白字符不计入字段宽度。

可用以下转换：

**`%`** 匹配字面量 `%`。即格式字符串中的“`%%`”匹配单个输入 `%` 字符。不进行转换，也不发生赋值。

**`b`** 匹配可选带符号的二进制整数；下一个指针必须是指向 `unsigned int` 的指针。

**`d`** 匹配可选带符号的十进制整数；下一个指针必须是指向 `int` 的指针。

**`i`** 匹配可选带符号的整数；下一个指针必须是指向 `int` 的指针。若整数以 `0b` 或 `0B` 开头则按二进制读取，以 `0x` 或 `0X` 开头则按十六进制读取，以 `0` 开头则按八进制读取，否则按十进制读取。仅使用与所用基数对应的字符。

**`o`** 匹配八进制整数；下一个指针必须是指向 `unsigned int` 的指针。

**`u`** 匹配可选带符号的十进制整数；下一个指针必须是指向 `unsigned int` 的指针。

**`x`, `X`** 匹配可选带符号的十六进制整数；下一个指针必须是指向 `unsigned int` 的指针。

**`a`, `A`, `e`, `E`, `f`, `F`, `g`, `G`** 匹配 [strtod(3)](/stdlib/strtod.3.md) 风格的浮点数。下一个指针必须是指向 `float` 的指针（除非指定了 `l` 或 `L`）。

**`s`** 匹配非空白字符序列；下一个指针必须是指向 `char` 的指针，且数组必须足够大以容纳整个序列和终止 `NUL` 字符。输入字符串在空白字符或最大字段宽度处停止，以先到者为准。若存在 `l` 限定符，下一个指针必须是指向 `wchar_t` 的指针，输入经 [mbrtowc(3)](/locale/mbrtowc.3.md) 转换后存入其中。

**`S`** 等同于 `ls`。

**`c`** 匹配 *width* 个字符的序列（默认为 1）；下一个指针必须是指向 `char` 的指针，且必须有足够空间容纳所有字符（不添加终止 `NUL`）。此处禁止通常跳过前导空白字符的行为。若要先跳过空白字符，在格式中使用显式空格。若存在 `l` 限定符，下一个指针必须是指向 `wchar_t` 的指针，输入经 [mbrtowc(3)](/locale/mbrtowc.3.md) 转换后存入其中。

**`C`** 等同于 `lc`。

**`[`** 匹配来自指定接受字符集的非空字符序列；下一个指针必须是指向 `char` 的指针，且必须有足够空间容纳字符串中所有字符及终止 `NUL` 字符。此处禁止通常跳过前导空白字符的行为。字符串由特定字符集内（或外）的字符组成；该集合由开括号 `[` 字符和闭括号 `]` 字符之间的字符定义。若开括号后的第一个字符是插入符 `^`，则该集合*排除*这些字符。要在集合中包含闭括号，将其作为开括号或插入符后的第一个字符；任何其他位置都会结束集合。连字符 `-` 也是特殊字符；置于两个其他字符之间时，它将中间所有字符加入集合。要包含连字符，将其作为最终闭括号前的最后一个字符。例如，`[^]0-9-]` 表示集合“除闭括号、零至九和连字符外的所有字符”。字符串在出现不在集合中（或使用插入符时在集合中）的字符或字段宽度耗尽时结束。若存在 `l` 限定符，下一个指针必须是指向 `wchar_t` 的指针，输入经 [mbrtowc(3)](/locale/mbrtowc.3.md) 转换后存入其中。

**`p`** 匹配指针值（如 [printf(3)](/stdio/printf.3.md) 中 `%p` 所打印的）；下一个指针必须是指向 `void` 的指针。

**`n`** 不期望任何输入；相反，从输入中迄今已消耗的字符数通过下一个指针存储，该指针必须是指向 `int` 的指针。这*不是*转换，但可用 `*` 标志抑制。

小数点字符由程序的 locale（类别 `LC_NUMERIC`）定义。

为向后兼容，“`%e0`”转换导致立即返回 `EOF`。

## 返回值

这些函数返回赋值的输入项数，在匹配失败时可少于预期甚至为零。零表示虽有可用输入但未赋值任何转换；通常这是由于无效的输入字符，例如 `%d` 转换遇到字母字符。若在任何转换之前发生输入失败（如文件结束），返回 `EOF`。若在转换开始后发生错误或文件结束，返回成功完成的转换数。

## 参见

[getc(3)](/stdio/getc.3.md), [mbrtowc(3)](/locale/mbrtowc.3.md), [printf(3)](/stdio/printf.3.md), [strtod(3)](/stdlib/strtod.3.md), [strtol(3)](/stdlib/strtol.3.md), [strtoul(3)](/stdlib/strtoul.3.md), [wscanf(3)](/stdio/wscanf.3.md)

## 标准

`fscanf`、`scanf`、`sscanf`、`vfscanf`、`vscanf` 和 `vsscanf` 函数遵循 ISO/IEC 9899:1999 ("ISO C99")。

## 历史

`scanf`、`fscanf` 和 `sscanf` 函数首次出现于 Version 7 AT\&T UNIX，`vscanf`、`vsscanf` 和 `vfscanf` 出现于 4.3BSD。

## 缺陷

`vfscanf` 的早期实现将 `%D`、`%E`、`%F`、`%O` 和 `%X` 视为带 `l` 修饰符的小写等价物。此外，`vfscanf` 将未知转换字符视为 `%d` 或 `%D`，取决于其大小写。此功能已移除。

数字字符串会截断为 512 个字符；例如，`%f` 和 `%d` 隐式为 `%512f` 和 `%512d`。

位置参数的 `%n$` 修饰符未实现。

`vfscanf` 函数族不能正确处理 `format` 参数中的多字节字符。
