关于fscanf与scanf输入流读取及回退机制的技术疑问
关于fscanf(scanf同理)中“读取”定义的疑问解答
C17 7.21.6.2.9条款规定:“从流中读取输入项……输入项定义为不超过指定域宽、且属于匹配输入序列或其前缀的最长输入字符序列。输入项后的首个字符(若存在)保持未读取状态……”
你之前认为,输入5X用%d读取时,5和X都会被读取,之后X再被回退到输入流。但根据上述条款描述,输入流的后续字符会先被“查看(peek)”,判断是否属于匹配序列——不符合的话就不会被读取,也就是X根本不会从流中移除,自然不需要回退。不过C17脚注289提到,fscanf最多会将一个输入字符回退到流中,这让你对“读取”的定义产生了疑问。
这里的“读取”特指从输入流中移除字符的操作,不包含仅查看但不移除的行为。
实际的匹配逻辑是:
- fscanf会逐个查看输入流中的字符,判断是否符合当前转换说明符的匹配规则;
- 符合规则的字符会被“读取”(从流中移除),纳入当前输入项;
- 遇到第一个不符合规则的字符时,这个字符不会被移除,保持未读取状态,当前输入项的读取就此停止。
那脚注289提到的回退是怎么回事?这是标准允许的一种实现细节。有些实现可能会采用“先读取再判断”的方式,而非“先查看再读取”。比如输入+X用%d读取时,先读取+(属于整数的合法前缀),再读取X后发现不符合数字要求,这时候就需要把X回退到流中。但标准要求最终效果必须和条款描述一致——输入项后的首个字符保持未读取状态,所以不管采用哪种实现方式,最多只会回退一个字符,保证流的状态符合规范。
简单总结:标准里的“读取”就是将字符从流中移除的操作;仅查看字符不属于“读取”。脚注提到的回退是实现层面的可选方式,不影响最终的流状态规则。
内容的提问来源于stack exchange,提问作者BenevolentDeity
相关产品推荐
相关产品推荐

