检测 scanf 格式字符串中常量的不匹配

use*_*520 5 c io scanf

man页面scanf

\n\n
\n

指令是以下之一:

\n\n
    \n
  • 一系列空白字符(空格、制表符、换行符等;请参阅 isspace(3))。该指令匹配输入中任意数量的空格,包括无空格。

  • \n
  • 普通字符(即除空格或\'%\'之外的字符)。该字符必须与输入的下一个字符完全匹配。(强调我的)

  • \n
  • 转换规范,以“%”(百分比)字符开头。输入的字符序列将根据此规范进行转换,并将结果放置在相应的指针参数中。如果下一项输入与转换规范不匹配,则转换失败\xe2\x80\x94这是匹配失败。

  • \n
\n
\n\n

现在,考虑以下代码:

\n\n
#include <stdio.h>\n\nint main(void)\n{\n    const char* fmt = "A %49s B";\n    char buf[50];\n\n    printf("%d\\n", sscanf("A foo B", fmt, buf));            // 1\n    printf("%d\\n", sscanf("blah blaaah blah", fmt, buf));   // 0\n    printf("%d\\n", sscanf("A blah blah", fmt, buf));        // 1\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

第 1 行和第 3 行会打印出来1,因为“A”与“A”的匹配成功,“foo”/“blah”与 的匹配也成功%s。第 2 行打印,0因为“A”无法与“blah”匹配,因此解析在那里停止。

\n\n

这一切都很好,也很符合逻辑,但是我有什么办法可以检测到在所有转换规范都成功匹配和分配之后发生了匹配失败吗?在这种情况下,返回的值scanf将是我的格式字符串中的转换说明符的数量,因此直到最后我都无法使用它来判断匹配是否成功。

\n\n

换句话说:sscanf第 3 行中输入的字符串不是“有效”的,因为它不符合 格式A [something] B。我可以用来scanf检测这一点,还是strtok我唯一的选择?

\n

chu*_*ica 5

" %n"在格式末尾使用 a 。

指令:
" "扫描 0 个或多个空白。它不会失败。
"%n"保存到目前为止解析的字符数(作为int)。它不会失败。

设置n为 0 并测试以查看它是否发生变化。仅当前面的整个格式成功时才会发生更改。还测试扫描是否以空字符结束 - 从而检测跟踪不需要的文本。

添加的" ",虽然是可选的,但如果非常有用,因为通常是尾随空格(通常是 )'\n',则不会令人反感。它不需要对扫描的文本行进行预处理以删除其行尾。

#include <stdio.h>

void test(const char *s) {
  const char* fmt = "A %49s B %n";
  char buf[50];
  int n = 0;
  int cnt = sscanf(s, fmt, buf, &n);
  int success = n > 0 && s[n] == '\0';
  printf("sscanf():%2d  n:%2d  success:%d  '%s'\n", cnt, n, success, s);
}

int main(void) {
  test("A foo B");
  test("blah blaaah blah");
  test("A blah blah");
  test("A foo B ");
  test("A foo B x");
  test("");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

sscanf(): 1  n: 7  success:1  'A foo B'
sscanf(): 0  n: 0  success:0  'blah blaaah blah'
sscanf(): 1  n: 0  success:0  'A blah blah'
sscanf(): 1  n: 8  success:1  'A foo B '
sscanf(): 1  n: 8  success:0  'A foo B x'
sscanf():-1  n: 0  success:0  ''
Run Code Online (Sandbox Code Playgroud)

请注意,成功是由n一个人决定的。如果不成功,则buf不应使用目标扫描变量。如果需要部分结果,则使用 的返回值sscanf()


too*_*ite 3

如果您想解析更复杂的输入,请使用适当的解析器/词法分析器。否则,请查看%n 转换说明符

不消耗任何输入。相应的参数应该是一个指向有符号整数的指针,迄今为止通过调用 fscanf 函数从输入流读取的字符数将写入到该整数中。%n 指令的执行不会增加 fscanf 函数执行完成时返回的赋值计数。没有转换任何参数,但消耗了一个参数。如果转换规范包含赋值抑制字符或字段宽度,则行为未定义。

您可以多次使用它:在最后一次变量转换之后和最后一次。