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

后端 未结 2 1017
北荒
北荒 2021-01-12 12:40

I\'m using Russian locale settings on my PC.
If I would set:

class numpunct_withpoint: public numpunct
{
protected:
    /// Override the fun         


        
相关标签:
2条回答
  • 2021-01-12 13:12

    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.

    0 讨论(0)
  • 2021-01-12 13:29

    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");
    
    0 讨论(0)
提交回复
热议问题