【问题标题】:Determine if a string is an integer or a float in ANSI C确定字符串是 ANSI C 中的整数还是浮点数
【发布时间】:2010-09-09 20:37:05
【问题描述】:

仅使用 ANSI C,确定 C 样式字符串是整数还是实数(即浮点数/双精度数)的最佳方法是什么?

【问题讨论】:

    标签: c floating-point numbers


    【解决方案1】:

    不要使用 atoi 和 atof,因为这些函数在失败时返回 0。上次我检查 0 是一个有效的整数和浮点数,因此没有用于确定类型。

    使用 strto{l,ul,ull,ll,d} 函数,因为这些函数会在失败时设置 errno,并且还会报告转换数据的结束位置。

    strtoul:http://www.opengroup.org/onlinepubs/007908799/xsh/strtoul.html

    此示例假定字符串包含要转换的单个值。

    #include <errno.h>
    
    char* to_convert = "some string";
    char* p = to_convert;
    errno = 0;
    unsigned long val = strtoul(to_convert, &p, 10);
    if (errno != 0)
        // conversion failed (EINVAL, ERANGE)
    if (to_convert == p)
        // conversion failed (no characters consumed)
    if (*p != 0)
        // conversion failed (trailing data)
    

    感谢 Jonathan Leffler 指出我忘了先将 errno 设置为 0。

    【讨论】:

    • 对不起,我知道这很老了,但是在这一行中,我们没有任何errno? unsigned long val = strtoul(to_convert, &p, 10);正确的是 unsigned long errno = strtoul(to_convert, &p, 10);
    • @vodkhang 这是有效代码,但您可能必须使用#include ,具体取决于您的编译器。 errno 本质上是一个可以使用错误代码设置的全局变量。它可以实现为宏或“可修改的左值”。
    • errno 一个扩展为可修改左值的宏。通常它会扩展为(*__errno_location()) 或类似的。
    • 为了避免任何人头疼,您可能必须添加#include 才能工作。
    【解决方案2】:

    使用sscanf,您可以确定字符串是float 还是int 或其他类型,而无需特殊情况0,就像atoi 和atof 解决方案的情况一样。

    下面是一些示例代码:

    int i;
    float f;
    if(sscanf(str, "%d", &i) != 0) //It's an int.
      ...
    if(sscanf(str "%f", &f) != 0)  //It's a float.
      ...
    

    【讨论】:

    • 我很确定您需要根据 sizeof str 测试 sscanf 的返回值,以确保整个字符串都已转换,否则“%d”如果交给“1.374”就不会失败",它会返回 1。
    • 是的。这也可以通过首先测试 %f 来解决,但这会导致“1.”出现问题。就个人而言,我最喜欢您提出的解决方案。
    • @Patrick_O 根据字符串长度检查sscanf 的返回是行不通的,因为它返回的是成功转换的项目数,而不是用于转换的字符数。但%n 格式在这里可能会有所帮助。
    【解决方案3】:

    如果不能,atoi 和 atof 将转换或返回 0。

    【讨论】:

    • 当然 - 您的回答肯定涵盖了这种情况。
    • 我已更改我的显示名称以避免这种混乱!
    【解决方案4】:

    我同意 Patrick_O 的观点,即 strto{l,ul,ull,ll,d} 函数是最好的方法。不过有几点需要注意。

    1. 在调用函数之前将 errno 设置为零;没有任何功能可以为您做到这一点。
    2. 链接到的 Open Group 页面(我在注意到 Patrick 也链接到该页面之前访问过该页面)指出 errno 可能未设置。如果值超出范围,则设置为 ERANGE;如果参数无效,它可以设置(但同样,可以设置)为EINVAL。

    根据手头的工作,我有时会安排跳过返回的转换指针末尾的尾随空格,然后如果最后一个字符不是终止的 null '\0',则抱怨(拒绝)。或者我可以草率地让垃圾出现在最后,或者我可以接受可选的乘数,例如 'K'、'M'、'G'、'T' 表示千字节、兆字节、千兆字节、太字节……或任何其他基于上下文的要求。

    【讨论】:

      【解决方案5】:

      我想你可以单步遍历字符串并检查其中是否有任何. 字符。不过,这只是我脑海中浮现的第一件事,所以我相信还有其他(更好的)方法可以更加确定。

      【讨论】:

      • 还有 ',' 字符。不要忘记本地化。
      【解决方案6】:

      使用 strtol/strtoll(不是 atoi)检查整数。 使用 strtof/strtod(不是 atof)检查双打。

      atoi 和 atof 转换字符串的初始部分,但不告诉您它们是否使用了所有字符串。 strtol/strtod 告诉你字符转换后是否有多余的垃圾。

      所以在这两种情况下,请记住传入一个非空的 TAIL 参数,并检查它是否指向字符串的末尾(即 **TAIL == 0)。还要检查下溢和上溢的返回值(有关详细信息,请参阅手册页或 ANSI 标准)。

      还要注意 strod/strtol 会跳过初始空格,因此如果您想将带有初始空格的字符串视为格式错误,您还需要检查第一个字符。

      【讨论】:

        【解决方案7】:

        这实际上取决于您首先询问的原因。

        如果你只是想解析一个数字并且不知道它是浮点数还是整数,那么只解析一个浮点数,它也会正确解析一个整数。

        如果你真的想知道类型,也许是为了分类,那么你真的应该考虑按照你认为最相关的顺序测试类型。就像尝试解析一个整数,如果你不能,然后尝试解析一个浮点数。 (反过来只会产生更多的浮点数...)

        【讨论】:

          【解决方案8】:

          即使有尾随非数字字符,atoi 和 atof 也会转换数字。但是,如果您使用 strtol 和 strtod ,它不仅会跳过前导空格和可选符号,还会为您留下一个指向不在数字中的第一个字符的指针。然后您可以检查其余部分是否为空格。

          【讨论】:

            【解决方案9】:

            好吧,如果你不想使用像 strtoul 这样的新函数,你可以添加另一个 strcmp 语句来查看字符串是否为 0。

            if(atof(token) != NULL || strcmp(token, "0") == 0)
            

            【讨论】:

            • 这认为“0.0”(及其其他变体)不是数字。
            猜你喜欢
            • 2018-03-20
            • 2022-01-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-05-14
            • 2016-05-15
            • 1970-01-01
            相关资源
            最近更新 更多