如何使用0的scanf宽度说明符?

时间:2013-05-29 16:06:58

标签: c scanf

如何使用0的扫描宽度说明符? 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()格式? / p>

2 个答案:

答案 0 :(得分:10)

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

  

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

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

答案 1 :(得分:4)

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

  

在%之后,以下顺序出现:

     

- 可选的赋值抑制字符*。

     

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

     

...

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

  

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

通过读取宽度为0的字段并将其作为字符串(空字符串)分配到Dest,您希望实现什么?你想解决哪个实际问题?似乎更清楚的是只分配*Dest = '\0';