7

如何使用 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' 

My question is about the last line. It seems that a 0 width results in no width limitation rather than a width of 0. If this is correct behavior or UB, I'll have to approach the zero width situation another way or are there other scanf() formats to consider?

4

2 回答 2

10

The maximum field width specifier must be non-zero. C99, 7.19.6.2:

The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The format is composed of zero or more directives: one or more white-space characters, an ordinary multibyte character (neither % nor a white-space character), or a conversion specification. Each conversion specification is introduced by the character %. After the %, the following appear in sequence:
— An optional assignment-suppressing character *.
An optional nonzero decimal integer that specifies the maximum field width (in characters).
— An optional length modifier that specifies the size of the receiving object.
— A conversion specifier character that specifies the type of conversion to be applied.

So, if you use 0, the behavior is undefined.

于 2013-05-29T16:44:12.033 回答
4

This came from 7.21.6.2 of n1570.pdf (C11 standard draft):

After the %, the following appear in sequence:

— An optional assignment-suppressing character *.

— An optional decimal integer greater than zero that specifies the maximum field width (in characters).

...

It's undefined behaviour, because the C standard states that your maximum field width must be greater than zero.

An input item is defined as the longest sequence of input characters which does not exceed any specified field width and ...

What is it you wish to achieve by reading a field of width 0 and assigning it as a string (empty string) into Dest? Which actual problem are you trying to solve? It seems more clear to just assign like *Dest = '\0';.

于 2013-05-29T16:44:43.357 回答