【问题标题】:C++: atof() has wrong behaviourC++:atof() 行为错误
【发布时间】:2013-07-19 09:27:58
【问题描述】:

我正在使用库将 Wavefront .obj 文件加载到我的 OpenGL 应用程序 (tinyobjloader) 中。我注意到加载对象时出现错误。当我加载一个坐标为例如的对象时。 0.9999999 设置为 0。通过调试我发现以下方法会产生这种行为:

static inline float parseFloat(const char*& token)
{
    token += strspn(token, " \t");
    float f = (float)atof(token);
    token += strcspn(token, " \t\r");
    return f;
}

所以 atof() 以某种方式返回一个 int,而不是一个 float。我读到有些编译器在使用 atof() 时不包含“stdlib.h”,结果是 atof() 返回一个整数。

奇怪的是,即使我包含“stdlib.h”,错误仍然存​​在。我不知道是什么导致了这种行为。

有什么想法吗?

【问题讨论】:

  • 确保使用gcc -Wall ...(或等效项,即启用警告)进行编译。
  • 为什么不使用 std::istringstream?
  • 这是一个外部库。这就是我不使用 std::stringstream 的情况。
  • 什么是编译器、操作系统、版本?
  • 那么“0,9999999”呢

标签: c++ std atof


【解决方案1】:

标准对 atof 说:

除了错误时的行为,它等价于 strtod(nptr,(char**)NULL)

所以你的返回 '0' 与不能代表它的浮点数或类似的无关。

您是否会使用 strtod 来代替(当 stringstreams 不是一个选项时您可能应该使用它,只是为了能够报告错误),那么您可能会注意到它在 . 处停止解析。

这强烈表明您正在使用等待 , 而不是 . 作为小数点分隔符的语言环境。根据您的应用程序如何使用语言环境,您可能希望使用正确设置的环境变量(例如LC_NUMERIC=C)运行它,或者在任何解析之前自己执行setlocale(LC_NUMERIC,"C");

在任何情况下,您都应该分析您的应用程序中谁在使用依赖于语言环境的事物,以及用于什么目的,以免与它们发生冲突。另一种可能的方法是在任何地方都需要依赖于语言环境的输入,因此每个人都需要以, 作为小数分隔符将数字提供给您。

【讨论】:

    【解决方案2】:

    您可以查看 atof here 的文档。一些浮点数不能用 32 位表示,因此会出现错误,返回的值为零。

    //Try these 
    float f = 0.9999999 ;
    cout << atof("0.9999999") << " " << f << endl;//output is 1 1 
    

    所以你看到的是一个有效的行为。 你可以试试strtod()

    【讨论】:

    • 在这两种情况下 - atof() 和 strtod() - 第一个输出我得到一个零。
    • 来自标准(关于atof):“除了错误的行为,它相当于strtod(nptr,(char**)NULL)”所以它必须解析和四舍五入,而不是返回0。
    • @TimV: strtod 期望 , 而不是 .?
    • 有些东西不能完全表示,但这不是 0.9999999 变成 0 的借口
    • @TimV:这不是问题所在。我在问您的 strtod 是否期望,而不是 .. 尝试一下。 strtod 取决于语言环境。
    猜你喜欢
    • 1970-01-01
    • 2020-06-16
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    相关资源
    最近更新 更多