与地点无关的"atof"?

tom*_*ash 21 c++ locale atof

我正在解析固定NMEA句子中的GPS状态条目,其中地理分钟的一小部分总是在一段时间之后.但是,在locale将逗号定义为小数分隔符的系统上,atof函数忽略句点和整数小数部分.

处理这个问题的最佳方法是什么?存储在字符数组中的长/纬度字符串,如果重要的话.

示例代码:

m_longitude = atof((char *)pField); 
Run Code Online (Sandbox Code Playgroud)

哪里

pField[] = "01000.3897"; 
Run Code Online (Sandbox Code Playgroud)

跨平台项目,为Windows XP和CE编译.

评论解决方案:

接受的答案更优雅,但这个答案(和评论)也值得快速解决

rjn*_*son 16

你总是可以使用(模数错误检查):

#include <sstream>
...

float longitude = 0.0f;
std::istringstream istr(pField);

istr >> longitude;
Run Code Online (Sandbox Code Playgroud)

标准iostream默认使用全局语言环境(反过来应该初始化为经典(美国)语言环境).因此,除非有人以前将全局语言环境更改为其他内容,否则上述内容应该可以正常工作,即使您在非英语平台上运行也是如此.要确保使用所需的语言环境,请创建一个特定的语言环境,并在读取之前使用该语言环境"填充"该流:

#include <sstream>
#include <locale>

...
float longitude = 0.0f;
std::istringstream istr(pField);

istr.imbue(std::locale("C"));
istr >> longitude;
Run Code Online (Sandbox Code Playgroud)

作为旁注,我通常使用正则表达式来验证NMEA字段,将字段的不同部分提取为捕获,然后使用上述方法转换不同的部分.NMEA经度字段中小数点前面的部分实际上格式化为"DDDMM.mmm ..",其中DDD对应度数,MM.mmm到分钟(但我猜你已经知道了).

  • C++有一个直接引用C语言环境的函数:`std :: locale :: classic()`因此不需要通过`std :: locale("C")`进行临时创建. (4认同)

MSa*_*ers 7

我曾经做过的一个讨厌的解决方案是sprintf()0.0f并从输出中获取第二个字符.然后在输入字符串中替换'.' 通过那个角色.这解决了逗号大小写,但如果区域设置定义了其他小数分隔符,也可以使用.

  • localeconv(在<locale.h>中)返回一个指向struct的指针,该decimal的decimal_point成员包含该值.请注意,指针有效直到下一个localeconv()或setlocale() (4认同)

Kaz*_*nov 7

这个问题很老了,但与此同时,在 C++ 中,我们得到了一个“与语言环境无关”的 atof:

std::from_chars(及其兄弟std::to_chars),在 c++17 中添加,提供与语言环境无关的浮点扫描(和格式)。它们位于 header 中<charconv>

您可以在此处阅读有关它们的更多信息:

https://en.cppreference.com/w/cpp/utility/from_chars

https://en.cppreference.com/w/cpp/utility/to_chars

我推荐 Stephan T. Lavavej 关于这两个工具的精彩演讲,这是他谈论使用 std::from_chars 部分的链接:https ://youtu.be/4P_kbF0EbZM ? t = 1367

我举了一个简短的例子:

#include <charconv>
#include <iostream>
#include <system_error>

int main()
{
    char buffer[16] { "123.45678" };
    float result;
    auto [p, ec] = std::from_chars(std::begin(buffer), std::end(buffer), result);
    if(ec == std::errc{})
        std::cout << result;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,至于今天 (05.06.2020) 只有 MSVC 支持这些带有浮动类型的函数。有效地实施它们被证明是一个大问题。

@edit (27.04.2021) 今天发布的 libstdc++ 稳定版 GCC 11.1 增加了对 float-type 的支持<charconv>。然而,这个实现似乎不符合标准——它需要将文本复制到另一个缓冲区并strto(f/d/ld)使用默认的 C 语言环境调用并设置浮动环境,从errno. 在极其奇怪的情况下,它可以在下面分配、抛出和捕获异常。你可以在这里找到实现:https : //github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B17/floating_from_chars.cc#L304