sscanf读取字符串,但%n返回0

时间:2016-01-11 19:30:06

标签: c gcc scanf

我正在查看一段代码,他的意图是从多行字符串中一次读取一行,并使用每行的前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。

2 个答案:

答案 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规范)。

请记住,格式字符串中的空格等同于数据中的可选空格。