Search code examples
c++g++localeclang++setlocale

Why does std::locale("").name() give different results on clang and gcc?


Compiling and running the following code on my machine (MacOS 10.14.x) results in printing an empty string on clang++ and throws a runtime error on g++. Why?

#include <locale>
#include <iostream>


int main()
{
  std::cout << "User-preferred locale setting is " <<
    std::locale("").name().c_str() << '\n';

  return 0;
}
$ clang++ locale.cc
$ ./a.out 
User-preferred locale setting is 


$ g++-mp-8 locale.cc 
$ ./a.out 
terminate called after throwing an instance of 'std::runtime_error'
  what():  locale::facet::_S_create_c_locale name not valid
User-preferred locale setting is Abort trap: 6

$ clang++ --version
clang version 7.0.1 (tags/RELEASE_701/final)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /opt/local/libexec/llvm-7.0/bin

$ g++-mp-8 --version
g++-mp-8 (MacPorts gcc8 8.3.0_0) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

At this time, I don't think it is a MacOS issue as running the example on cppreference.com also yields different results.

You can try it yourself for different compiler versions at: https://en.cppreference.com/w/cpp/locale/locale/name

In any case, it doesn't report the same as:

#include <locale>
#include <iostream>
#include <string>

int main()
{
  std::cout << "User-preferred locale setting is "
            << setlocale(LC_ALL, "") << "\n";

  return 0;
}

Which returns the same result ("en_US.UTF-8") for both compilers.

What am I missing?


Solution

  • You are right "The set of valid string argument values is "C", "", and any implementation-defined values..." But if you try to set to an unknown local (that may be returned by the local("")) it will throw a run-time error.

    Take a look at the source code of libstdc++-v3/config/locale/gnu/c_locale.cc

    locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s, __c_locale __old)
    {
        __cloc = __newlocale(1 << LC_ALL, __s, __old);
        if (!__cloc)
        {
            // This named locale is not supported by the underlying OS.
            __throw_runtime_error(__N("locale::facet::_S_create_c_locale name not valid"));
        }
    }
    

    __newlocale function is the one to blame. its a C function which will handle the conversion of the values passed to it.

    on MAC-OS it seems that libstdc++ is not handling correctly the "" value and even does ton of problems with a lot of locales.

    Its a well known issue in libstdc++ (which is used by g++). you can find it in multiple places easily, bug report 1,bug report 2, example 1. As you can see currently the libstdc++ supports only the "C" locales.

    I say use ICU :)