【问题标题】:parse decimal string with sscanf用 sscanf 解析十进制字符串
【发布时间】:2014-01-30 19:37:09
【问题描述】:

我想将字符串解析为整数。 字符串可以包含任何数据,包括无效或浮点整数。这是我的代码,它显示了我如何使用sscanf()

errno = 0;
uint32_t temp;
int res = sscanf(string, "%"SCNu32, &temp);
if (0 != errno || 1 != res)
{
    return HEX_ECONVERSION;
}

作为参数传递的字符串。

我预计此代码会在 "3.5" 数据上失败。但不幸的是,sscanf()"3.5" 截断为3 并将其写入temp 整数。 怎么了?

我是否不当使用sscanf()?以及如何使用sscanf 来完成这个任务,而不需要编写手写解析器(直接调用strtoul() 或类似的方法)。

【问题讨论】:

    标签: c linux glibc scanf


    【解决方案1】:

    3 是一个有效整数。不幸的是,sscanf 不够复杂,无法向前看并检测到 3.5float 并且不会给您任何结果。

    尝试使用strtol 并测试返回指针以查看它是否解析了整个字符串。

    【讨论】:

      【解决方案2】:

      使用扫描在缓冲区中的"%n" 记录。
      我们可以使用它来确定是什么停止了扫描。

      int n;
      int res = sscanf(string, "%"SCNu32 " %n", &temp, &n);
      if (0 != errno || 1 != res || string[n] != '\0')
        return HEX_ECONVERSION;
      

      附加" %n" 表示忽略后面的空白,然后记下缓冲区位置。如果没有像".5" 这样的额外垃圾,string[n] 将指向空终止符。


      确保在设置了temp 之后测试n。这是在上面使用1 != res 完成的。

      "%n" 不影响sscanf() 返回的值。

      【讨论】:

      • 我看到在这里你甚至不需要测试1 != res 好像字符串已完全消耗string[n] 将始终指向'\0',在另一种情况下,无论哪个值具有@ 987654334@ 会出错。我说的对吗?
      • @likern 通过首先在... 1 != res || string[n] != '\0' 中测试res,我们知道string[n] != '\0' 只有在res 的值为1 时才会执行。所以我们知道扫描转换通过@987654339 @。扫描转换在" %n" 中的" " 上永远不会停止,因此已知扫描到达"%n"n 具有合法值。如果res < 1,那么扫描永远不会通过"%"SCNu32,因此sscanf() 没有设置n。但也许我错过了你的意思?
      • 不,可能我错了。我以为我可以删除 1 != res 检查何时使用 string[n] != '\0'
      • @likern 代码可以通过int n = 0; 和后来的if (0 != errno || n > 0 || string[n] != '\0') 遵循您的新想法,但这并不能节省太多,并且会丢失EOF 检测。你的if (... || 1 != res || ...) 更好。
      【解决方案3】:

      sscanf 只解析它可以解析的部分字符串。您可以为其添加其他格式,例如"%d%s"。如果%s 说明符捕获非空字符串(如.5),则抛出错误。

      【讨论】:

      • 这是否意味着sscanf()甚至不表示error?只能使用“%d%s”之类的技巧吗?
      • 有效字符串后的多余字符不是错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-21
      • 2016-05-07
      • 1970-01-01
      • 2019-08-03
      • 2015-08-02
      • 1970-01-01
      • 2020-04-28
      相关资源
      最近更新 更多