在C中将只读字符数组转换为float而不使用null终止

时间:2015-03-12 18:36:45

标签: c floating-point

我正在寻找一个类似下面的C函数,它解析一个表示浮点值的长度终止的char数组,并将该值作为float返回。

float convert_carray_to_float( char const * inchars, int incharslen ) {
 ...
}

约束:

  1. inchars[incharslen]处的字符可能是数字或其他字符,可能会混淆常用的标准转换例程。
  2. 不允许例程调用inchars[incharslen] = 0来创建一个z终止的字符串,然后使用典型的库例程。甚至不允许在返回之前修补z覆盖的字符。
  3. 显然,可以将char数组复制到新的可写char数组中并在末尾追加null,但我希望避免复制。我关心的是表现。
  4. 这将经常被调用,所以我希望这样做尽可能高效。我很乐意编写自己的例程来解析和构建浮点数,但如果这是最好的解决方案,我会对在C中执行此操作的最有效方法感兴趣。

    如果您认为删除约束3确实是实现高性能的方法,请解释原因并提供您认为比维护约束3的解决方案更好的示例。

2 个答案:

答案 0 :(得分:1)

这是一个非常好的大纲。

不确定它涵盖所有情况,但它显示了大部分流程:

float convert_carray_to_float(char const * inchars, int incharslen)
{
    int Sign = +1;
    int IntegerPart = 0;
    int DecimalPart = 0;
    int Denominator = 1;
    bool beforeDecimal = true;

    if (incharslen == 0)
    {
        return 0.0f;
    }

    int i=0;
    if (inchars[0] == '-')
    {
        Sign = -1;
        i++;
    }
    if (inchars[0] == '+')
    {
        Sign = +1;
        i++;
    }

    for( ; i<incharslen; ++i)
    {
        if (inchars[i] == '.')
        {
            beforeDecimal = false;
            continue;
        }

        if (!isdigit(inchars[i]))
        {
            return 0.0f;
        }

        if (beforeDecimal)
        {
            IntegerPart = 10 * IntegerPart + (inchars[i] - '0');
        }
        else
        {
            DecimalPart = 10 * DecimalPart + (inchars[i] - '0');
            Denominator *= 10;
        }
    }

    return Sign * (IntegerPart + ((float)DecimalPart / Denominator));
}

答案 1 :(得分:1)

在* BSD libcs​​中使用的David Gay的实现可以在这里找到:https://svnweb.freebsd.org/base/head/contrib/gdtoa/最重要的文件是strtod.c,但它需要一些头文件和实用程序。每次更新字符串指针时修改它以检查终止将是一些工作,但不是很糟糕。

但是,您可能会认为额外检查的成本与将字符串复制到已知长度的临时缓冲区的成本相当,特别是如果字符串很短且已知长度,如您的示例中所示缓冲区包含3字节无限数字。在大多数体系结构中,如果数字长度不超过8个字节并且您小心确保缓冲区有一些尾部空间,则可以以非常低的成本使用单个8字节未对齐内存访问进行复制。 / p>