I work on Ubuntu and use an english keyboard.When I want to parse float from string in cpp using "strtof" function it is assuming commas, instead of dots as floating point. As a known solution I tried to use setlocale(LC_NUMERIC, "C") however this only helps within the same function scope where strtof is called. However If I need to add setlocale to every function scope it would take too much time. I tried to do this in main function, unfortunately only fixed the problem in the scope of main.
How to make it globally working?
You can set the global locale:
std::locale::global(std::locale("C"));//default.
Which should affect all functions which rely on the global locale.
Note that cout (and I presume cin and cerr) are imbued with the global locale at the moment they are created. Even if the first line of your code sets the global locale, the streams may have been created earlier, so you must imbue the stream with the new locale.
If you need locale specific behavior elsewhere, but don't want your number formatting messed with by default, boost::locale solved this issue -- you can see this question:What are the tradeoffs between boost::locale and std::locale?
Here's an example of output, but parsing behavior is identical:
auto demo = [](const std::string& label)
{
float f = 1234.567890;
std::cout << label << "\n";
std::cout << "\t streamed: " << f << "\n";
std::cout << "\t to_string: " << std::to_string(f) << "\n";
};
std::locale::global(std::locale("C"));//default.
std::cout.imbue(std::locale()); // imbue cout with the global locale.
demo("c locale");
std::locale::global(std::locale("de_DE"));//default.
std::cout.imbue(std::locale()); // imbue cout with the global locale.
demo("std de locale");
boost::locale::generator gen;
std::locale::global(gen("de_DE.UTF-8"));
std::cout.imbue(std::locale()); // imbue cout with the global locale.
demo("boost de locale");
Which provides the following result:
c locale
streamed: 1234.57
to_string: 1234.567871
std de locale
streamed: 1.234,57
to_string: 1234,567871
boost de locale
streamed: 1234.57
to_string: 1234,567871
Related
This is a follow up question to:
std::isgraph asserts, how to fix?
After setting locale to "en_US.UTF-8", std::isgraph no longer asserts.
However, the unicode character 架 (U+67B6) is reported as false in the same function. What is going on ?
It's a unicode built on Windows platform.
If you want to test characters that are too large to fit in an unsigned char, you can try using the wide-character versions, or a Unicode library as already suggested (Which is really the better option for portable code, as it removes any system or locale based differences in behavior).
This program:
#include <clocale>
#include <cwctype>
#include <iostream>
int main() {
wchar_t x = L'\u67B6';
char *loc = std::setlocale(LC_CTYPE, "");
std::wcout << "Using locale " << loc << ".\n";
std::wcout << "Character " << x << " is graphical: " << std::boolalpha
<< static_cast<bool>(std::iswgraph(x)) << '\n';
return 0;
}
when compiled and ran on my Ubuntu test system, outputs
Using locale en_US.utf8.
Character 架 is graphical: true
You said you're using Windows, but I don't have a Windows computer available for testing, so I can't confirm if this'll work there or not.
std::isgraph is not a Unicode-aware function.
It's an antiquity from C.
From the documentation:
The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF.
It only takes int because .. it's an antiquity from C. Just like std::tolower.
You should be using something like ICU instead.
It seems like only the "C" locale is working with MinGW. I tried the example found here and no commas were added even though the system locale is set to Canada.
#include <iostream>
#include <locale>
int main()
{
std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
// on startup, the global locale is the "C" locale
std::wcout << 1000.01 << '\n';
// replace the C++ global locale as well as the C locale with the user-preferred locale
std::locale::global(std::locale(""));
// use the new global locale for future wide character output
std::wcout.imbue(std::locale());
// output the same number again
std::wcout << 1000.01 << '\n';
}
The output is
User-preferred locale setting is C
100000
100000
I tried std::locale("en-CA") and get locale::facet::_S_create_c_locale name not valid at run time. I compile from CMD using g++. I'm running 64bit Windows 10.
Also I tried compiling this program found in the accepted answer here and got the compiler error 'LOCALE_ALL' was not declared in this scope.
How can I set the locale in MinGW to the system default or something explicit?
Had tried following code in Linux, but always return 'C' under different LANG settings.
#include <iostream>
#include <locale.h>
#include <locale>
using namespace std;
int main()
{
cout<<"locale 1: "<<setlocale(LC_ALL, NULL)<<endl;
cout<<"locale 2: "<<setlocale(LC_CTYPE, NULL)<<endl;
locale l;
cout<<"locale 3: "<<l.name()<<endl;
}
$ ./a.out
locale 1: C
locale 2: C
locale 3: C
$
$ export LANG=zh_CN.UTF-8
$ ./a.out
locale 1: C
locale 2: C
locale 3: C
What should I do to get current locale setting in Linux(like Ubuntu)?
Another question is, is it the same way to get locale in Windows?
From man 3 setlocale (New maxim: "When in doubt, read the entire manpage."):
If locale is "", each part of the locale that should be modified is set according to the environment variables.
So, we can read the environment variables by calling setlocale at the beginning of the program, as follows:
#include <iostream>
#include <locale.h>
using namespace std;
int main()
{
setlocale(LC_ALL, "");
cout << "LC_ALL: " << setlocale(LC_ALL, NULL) << endl;
cout << "LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << endl;
return 0;
}
My system does not support the zh_CN locale, as the following output reveals:
$ ./a.out
LC_ALL: en_US.utf8
LC_CTYPE: en_US.utf8
$ export LANG=zh_CN.UTF-8
$ ./a.out
LC_ALL: C
LC_CTYPE: C
Windows: I have no idea about Windows locales. I suggest starting with an MSDN search, and then opening a separate Stack Overflow question if you still have questions.
Just figured out how to get locale by C++, simply use an empty string "" to construct std::locale, which does the same thing as setlocale(LC_ALL, "").
locale l("");
cout<<"Locale by C++: "<<l.name()<<endl;
This link described differences in details between C locale and C++ locale.
For Windows use the following code:
LCID lcid = GetThreadLocale();
wchar_t name[LOCALE_NAME_MAX_LENGTH];
if (LCIDToLocaleName(lcid, name, LOCALE_NAME_MAX_LENGTH, 0) == 0)
error(GetLastError());
std::wcout << L"Locale name = " << name << std::endl;
This is going to print something like "en-US".
To purge sublanguage information use the following:
wchar_t parentLocateName[LOCALE_NAME_MAX_LENGTH];
if (GetLocaleInfoEx(name, LOCALE_SPARENT, parentLocateName, LOCALE_NAME_MAX_LENGTH) == 0)
error(GetLastError());
std::wcout << L"parentLocateName = " << parentLocateName << std::endl;
This will give you just "en".
A good alternative to consider instead of std::locale is boost::locale which is capable of returning more reliable information - see http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/locale_information.html
boost::locale::info has the following member functions:
std::string name() -- the full name of the locale, for example en_US.UTF-8
std::string language() -- the ISO-639 language code of the current locale, for example "en".
std::string country() -- the ISO-3199 country code of the current locale, for example "US".
std::string variant() -- the variant of current locale, for example "euro".
std::string encoding() -- the encoding used for char based strings, for example "UTF-8"
bool utf8() -- a fast way to check whether the encoding is UTF-8.
The default constructor of std::locale creates a copy of the global C++ locale.
So to get the name of the current locale:
std::cout << std::locale().name() << '\n';
The Problem
I'm developing an 32 bit unmanaged application in C++ on Windows using Visual Studio 2010. Forgive my lack of Windows knowledge as I usually develop on *nix.
Initially, in my program my calls to std::cout's stream insertion operator work fine. For example, the following statement outputs as expected:
std::cout << "hello" << std::endl;
However, the following code does not work:
std::cout << "\thello" << std::endl;
...call to DLL from Japanese company who won't respond to support requests...
std::cout << "\thello" << std::endl;
The above code prints:
hello
(inverted diamond symbol)hello(eighth note music symbol)(inverted o symbol)
Once I have called this DLL for the first time my output to std::cout is forever messed up. The symbols that are printed are not found in an ASCII table. The inverted o symbol is a single unicode char that looks like the letter 'o' but the black part of the o is white, and the white part is black(inverted colors). The music symbol is the unicode 8th note character.
Any ideas on why this is happening and how to fix it? It seems that this DLL is messing up how control characters (chars starting with \) are outputted.
What I have tried so far
I thought this might be a locale issue since the DLL is from a Japanese company. However, after the DLL call the locale is still "C" just as it was before the call. I use the following to query the locale:
printf ("Locale is: %s\n", setlocale(LC_ALL,NULL) );
I also thought this might be some kind of bizarre memory corruption but it seems that the \r\n gets replaced by (music symbol)(inverted o) whereas \t gets replaced by an inverted diamond symbol. There seems to be a regular "replace A by B" pattern for all the control chars, which would not indicate memory corruption.
Lastly, I also tried this:
std::cout << "blah" << '\r' << '\n';
and I see the same garbage characters created by:
std::cout << "blah" << std::endl;
Thanks in advance for any help and insight.
See whether this fixes it:
#include <iostream>
#include <locale>
int main()
{
std::cout << "\thello" << std::endl;
// ...call to DLL from Japanese company who won't respond to support requests...
locale mylocale(""); // or "C" // Construct locale object with the user's default preferences
std::cout.imbue( mylocale ); // Imbue that locale
std::cout << "\thello" << std::endl;
return 0;
}
Consult the documentation for that library whether
the change of locale is by design
it can be configured otherwise
You could perhaps associate another stream with cout
std::ostream cout2;
cout2.rdbuf(std::cout.rdbuf());
And use it. I'm sure that won't be thread safe. Flushing might be 'awkward' - but it should work
In C++ I've got a float/double variable.
When I print this with for example cout the resulting string is period-delimited.
cout << 3.1415 << endl
$> 3.1415
Is there an easy way to force the double to be printed with a comma?
cout << 3.1415 << endl
$> 3,1415
imbue() cout with a locale whose numpunct facet's decimal_point() member function returns a comma.
Obtaining such a locale can be done in several ways. You could use a named locale available on your system (std::locale("fr"), perhaps). Alternatively, you could derive your own numpuct, implement the do_decimal_point() member in it.
Example of the second approach:
template<typename CharT>
class DecimalSeparator : public std::numpunct<CharT>
{
public:
DecimalSeparator(CharT Separator)
: m_Separator(Separator)
{}
protected:
CharT do_decimal_point()const
{
return m_Separator;
}
private:
CharT m_Separator;
};
Used as:
std::cout.imbue(std::locale(std::cout.getloc(), new DecimalSeparator<char>(',')));
This is controlled by your program's locale.
How you set a program's default locale depends on the platform. On POSIX type platforms, it's with the LANG and LC_* environment variables, for instance.
You can force a particular locale -- different from the default -- within a C++ program by calling ios::imbue. Something like this might work:
#include <locale>
cout.imbue(std::locale("German_germany"));
The idea is to force a locale where comma is the decimal separator. You might need to adjust the "German_germany" string to get the behavior you want on your particular platform.
You need to impue the stream with a different locale, one whose num_punct (iirc) facet specifies a comma.
If your platform locale formats with commas, then
cout.imbue(locale(""));
should be sufficient.
To be precise, this is controlled by the std::numpunct<charT>::decimal_point() value. You can imbue() another locale with another decimal_point()
Old thread, but anyway ... One should be aware that using a std::locale makes the string "pretty", complete with correct decimal point, thousands separators and what not, depending on the platform and locale. Most probably, using imbue() will break any parsing of the string after it's formatted. For example:
std::ostringstream s;
std::locale l("fr-fr");
s << "without locale: " << 1234.56L << std::endl;
s.imbue(l);
s << "with fr locale: " << 1234.56L << std::endl;
std::cout << s.str();
Gives the following output:
without locale: 1234.56
with fr locale: 1 234,56
Using strtod() or similar on the second string probably won't work very well ... Also, the space between "1" and "2" in the second output string is a non-breaking one, making the string even prettier :-)
Very old thread, but anyway ... I had the problem to fill a text entry under Gtkmm-3.0 with the outcome of a distance calculation. To make things clearer I add an example, where I have concentrated some wisdoms of several posts I read the last days:
#include <locale>
// next not necessary, added only for clarity
#include <gtkmm-3.0/gtkmm.h>
Gtk::Entry m_Text;
// a distance measured in kilometers
double totalDistance = 35.45678;
std::stringstream str;
// I am using locale of Germany, pay attention to the _
str.imbue(std::locale("de_DE"));
// now we have decimal comma instead of point
str << std::fixed << std::setprecision(4) << std::setw(16) << totalDistance << " km";
// the wished formatting corresponds to "%16.4f km" in printf
m_Text.set_text(str.str());