I'm using Russian locale settings on my PC.
If I would set:
class numpunct_withpoint: public numpunct<char>
{
protected:
/// Override the function that gives the decimal separator.
char do_decimal_point() const
{
return '.';
}
};
...
locale loc(std::locale::classic(), new numpunct_withpoint);
std::locale::global(loc);
and than
printf("%f", 3.14);
Output is:
3,14
Decimal separator is "," not like in do_decimal_point function!
How can I change C locale settings for decimal separator with C++ locale?
Thanks for answer!
But, does C setlocale function make affect to C++ cout object?
setlocale(LC_NUMERIC, "C");
Would this make affect when printing decimal value via cout?
When you set the global C++ locale the C locale is modified as well. If you modify the C locale the global C++ locale is not modified.
The following demonstrates setting the C++ global locale.
#include <cstdio>
#include <clocale>
#include <fstream>
int main() {
const char * locale_name = "French_France.1252"; // or "fr_Fr.UTF-8" on Unix
double value = 1.2;
std::locale::global(std::locale(locale_name));
std::ofstream("out.txt") << "C++ " << value << '\n';
if (FILE *f = std::fopen("out.txt", "a")) {
std::fprintf(f, "C %1.1e\n", value);
std::fclose(f);
}
}
Both C and C++ output should use a comma decimal point.
C++ 1,2
C 1,2e+000
If you replace setting the C++ locale with setting the C locale, std::setlocale(LC_ALL, locale_name);
, then the output should change so that only the C output uses a comma decimal while the C++ output still uses the default period decimal symbol.
C++ 1.2
C 1,2e+000
However, the fact that setting the C++ locale affects the C locale does not make C locales extensible in the way that C++ locales are. Custom C++ facets will never be used by the C locale based functions. Instead you must rely on your system supporting some named locale that has the functionality you need.
Specifically, std::locale::global()
is defined to set the C locale using the name of the C++ locale you choose, if it has a name. The behavior is implementation defined if the C++ locale does not have a name. Also, C++ specifies that combining two named locales produces a named locale. Some implementations produce useful combined names that allow you mix C locale categories just by setting the C++ locale:
std::locale::global(std::locale(std::locale("ru_RU"), "C", std::locale::numeric));
With libstdc++ this produces a locale named:
LC_CTYPE=ru_RU;LC_NUMERIC=C;LC_TIME=ru_RU;LC_COLLATE=ru_RU;LC_MONETARY=ru_RU;LC_MESSAGES=ru_RU;LC_PAPER=ru_RU;LC_NAME=ru_RU;LC_ADDRESS=ru_RU;LC_TELEPHONE=ru_RU;LC_MEASUREMENT=ru_RU;LC_IDENTIFICATION=ru_RU
LC_CTYPE=ru_RU;LC_NUMERIC=C;LC_TIME=ru_RU;LC_COLLATE=ru_RU;LC_MONETARY=ru_RU;LC_MESSAGES=ru_RU;LC_PAPER=ru_RU;LC_NAME=ru_RU;LC_ADDRESS=ru_RU;LC_TELEPHONE=ru_RU;LC_MEASUREMENT=ru_RU;LC_IDENTIFICATION=ru_RU
So that the C locale is set to the same mixture between the "ru_RU" and "C" locales as the C++ locale.
Unfortunately other implementations choose less useful, though still technically conformant, behavior. In Visual Studio
std::locale::global(std::locale(std::locale("Russian_Russia.1251"), "C", std::locale::numeric));
produces a locale with the name "C". So while the C++ locale is the appropriate mixture of Russian and C locale categories, the C locale is simply set to "C". So on these platforms to mix C locale categories you must directly set the C locale:
// set the C++ locale first
std::locale::global(std::locale(std::locale("Russian_Russia.1251"), "C", std::locale::numeric));
// set the C locale second, because it will not overwrite the changes you made to the C++ locale
std::setlocale(LC_ALL, "Russian_Russia.1251");
std::setlocale(LC_NUMERIC, "C");
The C library does not use the same locale settings as C++. To override the locale used by printf
, use setlocale:
setlocale(LC_NUMERIC, "POSIX");
or similar.