sscanf和尾随字符

3

我正在尝试使用sscanf进行简单的测试和转换,但是在使用中遇到了一个问题——它忽略字符串中的尾随垃圾。我的示例代码如下:

char *arg = "some user input argument";
int val = 0;
if (sscanf(arg, "simple:%d", &val) == 1) {
    opt = SIMPLE;
} else if (strcmp(arg, "none") == 0) {
    opt = NONE;
} else {
    // ERROR!!!
}

这对于预期的输入正常工作,例如:

arg = "simple:2"  --> opt = SIMPLE  val = 2
arg = "none"      --> opt = NONE    val = 0

但是我的问题是,在“简单”值之后的 尾随 字符被默默地忽略了。

ACTUAL : arg = "simple:2GARBAGE" --> opt = SIMPLE  val = 2
DESIRED: arg = "simple:2GARBAGE" --> ERROR!!!

有没有一种简单的方法可以让sscanf报告尾随的垃圾?或者,由于我已经读过“scanf is evil”,是否有一个简单的(最好是一行)替代方案来解决上述问题?

谢谢hmjd,这回答了我的问题!用我的搜索词找不到它。希望这个问题能帮助其他人找到同样的解决方案。 - ɲeuroburɳ
scanf() 是有害的。sscanf() 不是 scanf(),如果使用得当,它可以正常工作。对 scanf() 最大的问题之一是它将 I/O 与解析结合在一起,当出现问题时,很难重新确定在 I/O 流中继续的位置。sscanf() 只进行解析,不执行 I/O。 - chux - Reinstate Monica
2个回答

8

sscanf()用于寻找额外的char,如果找不到则失败。

char ch;
// If _nothing_ should follow the `int`
if (sscanf(arg, "simple:%d%c", &val, &ch) == 1) Success();
// or if trailing white-space is OK
if (sscanf(arg, "simple:%d %c", &val, &ch) == 1) Success();

另一种成语解决方案使用%n
int n;
// If _nothing_ should follow the `int`
if (sscanf(arg, "simple:%d%n", &val, &n) == 1 && arg[n] == '\0') Success();
// or if trailing white-space is OK
if (sscanf(arg, "simple:%d %n", &val, &n) == 1 && arg[n] == '\0') Success();

简单而有效。我喜欢它。唯一的缺点是所有这些解决方案似乎都需要某种临时变量。但看起来没有任何绕过它的方法。 - ɲeuroburɳ
1
@ЙІeuroburЙі еҸҜд»ҘдҪҝз”Ёsscanf(arg, "simple:%d%c", &val, &arg[0])пјҢеӣ дёәеҪ“йҒҮеҲ°%cж—¶пјҢsscanf()еҝ…йЎ»и¶…иҝҮ&arg[0]гҖӮдҪҶиҝҷжңүзӮ№дёҚеӨӘдјҳйӣ…гҖӮ - chux - Reinstate Monica
哈哈。你也可以使用 sscanf(arg, "simple:%d%c", &val, (char*)&val)。:) 所有事情都相等的话,我更喜欢你的答案而不是你的巧妙方法。 :) - ɲeuroburɳ

4
您可以使用以下内容:
char rest[64] = "";
[...]
if ( sscanf(arg, "simple:%d%s", &val, rest) == 1 ) {

并测试 rest 的内容或长度。

这是因为在 %d 后面跟着的 %s 将会接受有效数字后的任意字符。您可以根据需要调整 rest 的大小。

在此处查看一个工作示例:here


3
这跟我发问题后一直尝试的方法类似。我认为使用"%s"转换时加上长度限定符可能更安全一些。例如:"simple:%d%1s",剩下的可以是一个char[2]。 - ɲeuroburɳ
2
该方法无法检测尾随的空格。虽然'%s'会吃掉任何有效数字后面的字符,但如果它只遇到尾随的空格字符,则不会保存任何内容在rest()中,仍将返回1 - chux - Reinstate Monica
@ɲeuroburɳ 在这个问题上说得好。这样,您就不必担心rest足够大了。 - szr
1
需要一个由@ɲeuroburɳ提出的长度来防止过多的尾随非空格字符。但是由于只需要检测到一个单一的出现,代码可以使用char rest[2]; ... sscanf(arg, "simple:%d%1s", &val, rest) ... - chux - Reinstate Monica
@chux 谢谢,关于尾随空格的观点很好。 - szr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接