How to make std::strtod() *not* depend on locale?

J

Juha Nieminen

I have made a program which parses strings in certain specified
format. This string format can contain numerical values in the format
understood by std::strtod().

The problem is: How std::strtod() interprets the string depends on
locale. This messes things up. For example, if the string to interpret
is "f(1,2)", in other words, a function call with two parameters, it
will work fine if the locale says that the decimal separator is a '.'
(as for example in the English locale), but it will mess up if the
locale says that the decimal separator is a ',' (as for example in the
Finnish locale). In the latter case std::strtod() will parse the entire
"1,2" as the number (resulting in the value 1.2), after which my parser
sees that only one parameter was given to the function even though the
function requires two, giving thus a syntax error.

Of course it also messes up things like "f(1.2,3.4)" in the latter
case, as std::strtod() will stop parsing at the '.' so my parser will
see that a '.' immediately follows a numerical value, which is against
syntax, and thus a syntax error once again happens.

(The string is actually parsed correctly in the latter case if you
write "f(1,2 , 3,4)", but it's a nuisance, and a nightmare to document!)

Is there any way to make std::strtod() ignore locale and always parse
the string in the same way?
 
M

Michael DOUBEZ

Juha Nieminen a écrit :
I have made a program which parses strings in certain specified
format. This string format can contain numerical values in the format
understood by std::strtod().

The problem is: How std::strtod() interprets the string depends on
locale. [snip]
Is there any way to make std::strtod() ignore locale and always parse
the string in the same way?

If you have made the program and not modified the locale, you should not
have any problem (IIRC it default to "C").
The C locale is a global resource: there is only one locale for the
entire application so you cannot change it for one function except
overriding it locally upon specific function call.

With C++ streams, you just use imbue() on your stream and many locales
can coexist; perhaps you could use them instead.

Michael
 
J

Juha Nieminen

Michael said:
If you have made the program and not modified the locale, you should not
have any problem (IIRC it default to "C").

The problem is that the exact same binary executable is behaving
differently in different systems which have different locales. More
precisely, as I said, strtod() is parsing numbers differently.
 
P

Pete Becker

The problem is that the exact same binary executable is behaving
differently in different systems which have different locales. More
precisely, as I said, strtod() is parsing numbers differently.

As it's supposed to. <g> It's the wrong tool. You could make it work by
saving the current locale, setting the locale to "C", doing the strtod,
and then restoring the original locale. Which just emphasizes that it's
the wrong tool.

Scan to the next comma or right parenthesis, saving the text in a
buffer. If the argument is supposed to be a floating point value, use
strtod on the buffer.
 
P

Pete Becker

As it's supposed to. <g> It's the wrong tool. You could make it work by
saving the current locale, setting the locale to "C", doing the strtod,
and then restoring the original locale. Which just emphasizes that it's
the wrong tool.

Scan to the next comma or right parenthesis, saving the text in a
buffer. If the argument is supposed to be a floating point value, use
strtod on the buffer.

Whoops, that just postpones the problem. Sorry for the noise.
 
M

Michael DOUBEZ

Juha Nieminen a écrit :
The problem is that the exact same binary executable is behaving
differently in different systems which have different locales. More
precisely, as I said, strtod() is parsing numbers differently.

What I mean is that if setlocale() is not invoked, the POSIX locale is
the default at entry to main() so that means you invoking setlocale
somewhere that mess up things - usually setlocale(LC_ALL,"") that takes
the environment locale.

You can enforce the locale to use '.' for floats:
setlocale(LC_NUMERIC,"C"); //to check

You could also locally use stringstream with a clean locale to perform
double conversion (boost::lexical_cast<> comes to mind).

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top