【问题标题】:How to use a scanf width specifier of 0?如何使用 0 的 scanf 宽度说明符?
【发布时间】:2013-05-29 16:06:57
【问题描述】:

如何使用 0 的 scanf 宽度说明符?
1) 不受限制的宽度(如 cywin gcc 版本 4.5.3 所示)
2) UB
3)别的东西?

我的应用程序(未显示)动态地将宽度说明符作为 scanf() 的较大格式字符串的一部分。它很少会在格式字符串的中间创建一个"%0s"。在这种情况下,%0s 的目标字符串只有 1 个字节的空间供 scanf() 存储 \0,上面的行为 #1 会导致问题。

注意:以下测试用例使用常量格式。

#include <memory.h>
#include <stdio.h>

void scanf_test(const char *Src, const char *Format) {
  char Dest[10];
  int NumFields;
  memset(Dest, '\0', sizeof(Dest)-1);
  NumFields = sscanf(Src, Format, Dest);
  printf("scanf:%d Src:'%s' Format:'%s' Dest:'%s'\n", NumFields, Src, Format, Dest);
}

int main(int argc, char *argv[]) {
  scanf_test("1234" , "%s");
  scanf_test("1234" , "%2s");
  scanf_test("1234" , "%1s");
  scanf_test("1234" , "%0s");
  return 0;
}

输出:

scanf:1 Src:'1234' Format:'%s' Dest:'1234'  
scanf:1 Src:'1234' Format:'%2s' Dest:'12'  
scanf:1 Src:'1234' Format:'%1s' Dest:'1'  
scanf:1 Src:'1234' Format:'%0s' Dest:'1234' 

我的问题是关于最后一行。似乎 0 宽度导致没有宽度限制,而不是 0 宽度。如果这是正确的行为或 UB,我将不得不以另一种方式处理零宽度情况,或者是否有其他 scanf() 格式需要考虑?

【问题讨论】:

  • 看起来%0s 被评估为%s。 0 被忽略。但我无法确认。我不知道是否有标准提及这种行为
  • 有一个* 格式规范来禁止分配。这会有帮助吗?
  • @mf_ UB 代表未定义的行为。
  • @Arkadiy * 抑制赋值的格式规范是一个新颖的想法。它会阻止 0 宽度的目标字符串接收数据,但不幸的是,scanf() 仍然会消耗输入字符串,不会为下一个地址不在正确位置的格式说明符留下任何内容。

标签: c scanf


【解决方案1】:

最大字段宽度说明符必须非零。 C99,7.19.6.2:

格式应该是一个多字节字符序列,以它的首字母开始和结束 转移状态。格式由零个或多个指令组成:一个或多个空格 字符、普通的多字节字符(既不是% 也不是空白字符),或者 转换规范。每个转换规范都由字符% 介绍。 在%之后,依次出现:
— 一个可选的赋值抑制字符*
一个可选的非零十进制整数,指定最大字段宽度(在 字符)。
— 一个可选的长度修饰符,指定接收对象的大小。
转换说明符字符,指定要应用的转换类型。

因此,如果您使用0,则行为未定义。

【讨论】:

    【解决方案2】:

    这来自 n1570.pdf(C11 标准草案)的 7.21.6.2:

    %后依次出现:

    ——一个可选的赋值抑制字符*。

    - 一个可选的大于零的十进制整数,用于指定 最大字段宽度(以字符为单位)。

    ...

    这是未定义的行为,因为 C 标准规定您的 最大字段宽度 必须大于零。

    输入项定义为输入字符的最长序列 不超过任何指定的字段宽度和...

    您希望通过读取宽度为 0 的字段并将其作为字符串(空字符串)分配给 Dest 来实现什么?您要解决哪个实际问题?像*Dest = '\0'; 这样分配似乎更清楚。

    【讨论】:

    • *未定义行为 此应用程序中scanf() 的格式是根据目标字符串的可用空间以及其他字段动态生成的。程序不提前知道宽度需要为0。因此使用*Dest = '\0';在一般情况下不起作用,但可以用于处理异常宽度= 0的情况。
    • @chux 好吧,我的程序对一副纸牌进行排序......但它有什么用途?为什么需要它?您要解决哪个实际问题?我不是要你描述你的解决方案;我要求你描述问题。
    • 应用程序使用文本文件来控制测试各种产品和产品功能的生产程序的操作。在解析配置文件时,它们可以存在其他配置,这些配置规定了某些字段预期的最大文本长度。正是这些其他配置文件允许指定宽度为 0,并且该 0 被传递给通用解析器。当通过 0 宽度时,只分配了 0+1 个字节来接收数据。如上所述,保存了太多字节。最后,现在将宽度配置为 0 是禁止的。
    • user315052 C99 参考和您的 C11 参考草案(可在线获得)是这些答案中最好的部分。我可以直接查找这些利基 C 问题。 RTFM - 阅读 fantastic 手册!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 2020-03-28
    相关资源
    最近更新 更多