Does std::locale::global make affect to printf() function?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-01 04:14:05

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!