如何使用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>
答案 0 :(得分:10)
最大字段宽度说明符必须为非零。 C99,7.19.6.2:
格式应为多字节字符序列,以其首字母开头和结尾 转移状态。格式由零个或多个指令组成:一个或多个空格 字符,普通的多字节字符(既不是
%
也不是空白字符),或者是 转换规范。每个转换规范都由字符%
引入。 在%
之后,以下顺序出现:
- 可选的赋值抑制字符*
- 可选的非零十进制整数,指定最大字段宽度(in 字符)。强>
- 可选的长度修饰符,用于指定接收对象的大小 - 转换说明符字符,用于指定要应用的转换类型。
因此,如果您使用0
,则行为未定义。
答案 1 :(得分:4)
这来自n1570.pdf(C11标准草案)的7.21.6.2:
在%之后,以下顺序出现:
- 可选的赋值抑制字符*。
- 一个大于零的可选十进制整数,用于指定 最大字段宽度(以字符为单位)。
...
这是未定义的行为,因为C标准规定您的最大字段宽度必须大于零。
输入项被定义为输入字符的最长序列 它不超过任何指定的字段宽度......
通过读取宽度为0的字段并将其作为字符串(空字符串)分配到Dest
,您希望实现什么?你想解决哪个实际问题?似乎更清楚的是只分配*Dest = '\0';
。