我正在查看一段代码,他的意图是从多行字符串中一次读取一行,并使用每行的前30个字符进行处理。我们遇到了sscanf将“buff”的内容复制到“list”中的情况,但“count”设置为0。
//这是有问题的代码:
void foo(char * buff)
{
char line[31] = {0};
int count = 0;
int result = sscanf(buff, "%30[^\n]%*c%n", line, &count);
printf("result = %d line = %s count = %d\n", result, line, count);
}
foo("test\n");
foo("test");
输出:
result = 1 line = test count = 5
result = 1 line = test count = 0
第二种情况下sscanf的返回表示一个字段读取,“line”包含“test”,所以显然,从输入中读取了四个字符。根据定义,%n应报告4。
答案 0 :(得分:2)
根据我的理解,格式说明符"%1024 [^ \ n]%* c%n"与你的字符串不匹配"测试":首先(部分"%1024 [^ \ n]"),你最多读取1024个字符(不包括' \ n' ;) - 那将是"测试"。然后(部分"%* c"),您尝试再读一个字符,但不要存储它。因为你的字符串"测试"已经被吃掉了,解析停止失败。最有可能的是,sscanf已经修改了到目前为止已处理的所有论据,这就是为什么" line"仍然已经包含字符串" test"。
这是我尝试过的代码:
#include <stdio.h>
void foo(const char *buff)
{
char line[32] = {0};
int count = 255;
int fields = 0;
fields = sscanf(buff, "%31[^\n]%n%*c", line, &count);
printf("line = \"%s\" count = %d fields = %d\n", line, count, fields);
}
int main() {
foo("test\n");
foo("test");
}
其中给出了以下输出:
line = "test" count = 4 fields = 1
line = "test" count = 4 fields = 1
格式字符串"%31[^\n]%*c%n"
我得到(并且,是的,也是1024):
line = "test" count = 5 fields = 1
line = "test" count = 255 fields = 1
与gcc 4.6.3。
答案 1 :(得分:2)
来自%n
系列函数的返回值中不会计算抑制分配和scanf()
转换规范。这意味着您无法分辨是否匹配了被抑制的分配,也无法判断%n
是否已处理,除非之后有分配 - 或者您初始化将由%n
转换分配的变量例如,带有负值的规范,看看之后是否有变化。
查看测试代码,转换两个输入字符串,以便读取test
;这是预期的,你看到了什么。
使用格式字符串"%31[^\n]%*c%n"
,在test
转换完成后,使用输入"test\n"
,抑制的分配转换成功(读取换行符),以便{{1}处理。但是,对于输入%n
,被抑制的赋值将失败(在读取"test"
后没有剩余的字符要处理),因此test
也不会被处理。出现问题时,处理会停止 - 格式字符串中的文字字符不匹配,或转换失败(无论是否禁止分配)。
因此,您看到的行为是标准所要求的(例如,参见sscanf()
的POSIX规范)。
请记住,格式字符串中的空格等同于数据中的可选空格。