【问题标题】:The scanf 'maximum field width' includes whitespace?scanf“最大字段宽度”包括空格?
【发布时间】:2019-04-08 21:19:11
【问题描述】:

假设我们有

int n;
sscanf(" 42", "%2d", &n);

n 应该是 4(“%2d”占的空格)还是 42(忽略空格,使 scanf 读取 3 个字符)?

ideone implementation 读取 3 个字符

【问题讨论】:

  • 来自 MacOS 上的手册页:“在转换开始之前,大多数转换都会跳过空白;此空白不计入字段宽度。”

标签: c language-lawyer standards


【解决方案1】:

sscanf() 的 POSIX 规范 对处理相当清楚:

格式是一个字符串,......由零个或多个指令组成。每个指令由以下之一组成: 一个或多个空白字符(<space><tab><newline><vertical-tab><form-feed>);一个普通字符(既不是 '%' 也不是空白字符);或转换规范。每个转换规范由字符'%'[CX]⌦或字符序列“%n$”,⌫之后依次出现:

作为转换规范的指令定义了一组匹配的输入序列,如下文针对每个转换字符所述。转换规范应按以下步骤执行。

应跳过输入的空白​​字符(由isspace 指定),除非转换规范包含[cCn 转换说明符。

应从输入中读取项目,除非转换规范包含n 转换说明符。输入项应定义为输入字节的最长序列(直到任何指定的最大字段宽度,可以根据转换说明符以字符或字节为单位测量),它是匹配序列的初始子序列。输入项之后的第一个字节(如果有)应保持未读状态。如果输入项的长度为0,则转换规范执行失败;这种情况是匹配失败,除非文件结尾、编码错误或读取错误阻止了来自流的输入,在这种情况下是输入失败。

如果转换规范 (%…) 跳过了空白,则它不计入字段宽度的一部分;跳过发生在任何计数之前。

C11 §7.21.6.2 The fscanf function 中的等效规范非常相似(当然,它不包括“C 扩展”标记)。

【讨论】:

    【解决方案2】:

    scanf 的“最大字段宽度”包括空格?

    [c 是。
    其他说明符不适用。
    "%n" 不适用。

    fscanf()(C11dr §7.21.6.2 7-9)

    7 ... 在以下步骤中执行转换规范:

    8 输入的空白​​字符(由 isspace 函数指定)被跳过,除非规范中包含 [cn 说明符。

    9 从流中读取输入项,...输入项定义为输入字符的最长序列,不超过任何指定字段width和....

    宽度应用在前导输入空白字符消耗之后。


    此外,当我阅读规范时,如果转换失败,输入的空白​​字符仍然会被消耗。

    【讨论】:

    • 最后一句增加了一点学习的新意。必须测试各种编译器是否一致地实现了这一点。如果那里有异常值,将删除注释。
    • @DavidC.Rankin 期待您的发现。
    • 当然,空白仍然被消耗——因为它是用ungetc 完成的,它只有一个字符保证回退。 @DavidC.Rankin
    • 哇,阅读 ungetc 的文档时的新发现 - 参数 ungetc 必须是 unsigned char
    • @AnttiHaapala fscanf() push back as if with ungetc() and ungetc() has "保证一个后推字符。如果在没有干预的情况下在同一流上调用 ungetc 函数太多次对该流进行读取或文件定位操作,该操作可能会失败。” IMO,黄鼠狼的话,允许推回不止一个,有时。 IOW,实现定义的行为。
    【解决方案3】:

    来自 BSD 手册页:

    除了这些标志之外,可能还有一个可选的最大字段宽度, 表示为十进制整数,介于 % 和转换之间。如果没有宽度 给定,使用默认的“无穷大”(有一个例外,如下);否则 在处理转换时最多扫描这么多字节。如果是 lc、ls 和 l[ 转换,字段宽度指定最大数量 将被扫描的多字节字符。在转换开始之前,大多数转换都会跳过空白;此空白不计入该字段 宽度。

    Linux 手册页有

    一个可选的十进制整数,它指定最大字段宽度。读 字符数在达到此最大值或不匹配时停止 找到字符,以先发生者为准。大多数转换丢弃初始 空白字符(例外情况如下所述),并且这些被丢弃 字符不计入最大字段宽度。字符串输入转换存储一个终止空字节('\0')来标记输入的结束;这 最大字段宽度不包括此终止符。

    两者都指定空格不计入字段宽度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-05
      • 2014-09-04
      • 2012-05-31
      • 2017-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      相关资源
      最近更新 更多