Locale-independent "atof"?
A nasty solution I've done once is to sprintf()
0.0f and grab the second character from the output. Then in the input string replace '.' by that character. This solves the comma case, but would also work if a locale defined other decimal separators.
You could always use (modulo error-checking):
#include <sstream>
...
float longitude = 0.0f;
std::istringstream istr(pField);
istr >> longitude;
The standard iostreams use the global locale by default (which in turn should be initialized to the classic (US) locale). Thus the above should work in general unless someone previously has changed the global locale to something else, even if you're running on a non-english platform. To be absolutely sure that the desired locale is used, create a specific locale and "imbue" the stream with that locale before reading from it:
#include <sstream>
#include <locale>
...
float longitude = 0.0f;
std::istringstream istr(pField);
istr.imbue(std::locale("C"));
istr >> longitude;
As a side note, I've usually used regular expressions to validate NMEA fields, extract the different parts of the field as captures, and then convert the different parts using the above method. The portion before the decimal point in an NMEA longitude field actually is formatted as "DDDMM.mmm.." where DDD correspond to degrees, MM.mmm to minutes (but I guess you already knew that).
This question is old, but in the meantime in C++ we got a "locale-independent" atof:
std::from_chars
(with its sibling std::to_chars
), added in c++17, provide locale-independent float scanning (and formatting). They are located in header <charconv>
.
You can read more about them here:
https://en.cppreference.com/w/cpp/utility/from_chars
https://en.cppreference.com/w/cpp/utility/to_chars
I recomment Stephan T. Lavavej wonderful talk about these two tools, here's the link to the part where he talks about using std::from_chars: https://youtu.be/4P_kbF0EbZM?t=1367
And a short example by me:
#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;
}
Unfortunately, as for today (05.06.2020) only MSVC supports these functions with floating types. Implementing them efficiently turned out to be a big problem.
@edit (27.04.2021) libstdc++ released today with stable GCC 11.1 adds support for floating-type <charconv>
. However, this implementation seems to be not standard-compliant - it needs to copy the text into another buffer and calls strto(f/d/ld)
with default C locale and set Floating Environment, taking error from errno
. In extremely weird cases it can allocate, throw and catch exceptions underneath. You can find the implementation here:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B17/floating_from_chars.cc#L304