5

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?

tegtmeye
  • 132
  • 1
  • 10
  • "throws a runtime error on g++" Is there any more information? – L. F. Oct 05 '19 at 07:25
  • Throws std::runtime_error. I edited the question to add MWE compile and results. – tegtmeye Oct 05 '19 at 13:25
  • the exception message seems pretty specific: the locale name is not valid. documentation says the constructor can throw std::runtime_error if the operating system has no locale with that specified name (in this case, the empty string). is there a reason you're using the empty string rather than the no-argument constructor? – jdigital Oct 05 '19 at 19:59
  • 1
    From c++ standard "22.1.1.2 locale constructors and destructor", "The set of valid string argument values is "C", "", and any implementation-defined values." which is consistent with C in that the empty string obtains the user-preferred local from environment (typically set with the LANG or equivalent environmental variable). From my read of the documentation, the no-argument constructor should represent the locale set from the most recent call to std::locale::global which is not the same thing. – tegtmeye Oct 06 '19 at 03:55
  • I tried both versions for both compilers, and it worked fine, no error and same results, as you can see here: https://godbolt.org/z/h53ED3 – Fareanor Oct 14 '19 at 06:46
  • Could be a bug in MacPorts gcc8 8.3.0_0. Here's a link to the current draft's version of [[locale.cons](http://eel.is/c++draft/locale.cons#6)]. It's easy to trigger the error but I haven't found a way to make `g++` trigger without `clang++` triggering too: https://godbolt.org/z/tqeAbq – Ted Lyngmo Oct 14 '19 at 10:41

2 Answers2

0

The differences probably come from the fact that clang++ uses libc++ whereas g++ uses libstdc++. The function std::locale() is defined in either of these, and the implementations differ.

You can check this with strace (if available), as follows:

$ strace -e file ./a.out
...
open("/usr/lib/.../libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
...

In this example, the libstdc++ is used.

user803422
  • 2,636
  • 2
  • 18
  • 36
0

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 :)

Shlomi Hassid
  • 6,500
  • 3
  • 27
  • 48
  • Thanks. I'm marking the question as answered. Basically I was trying to understand why it appears that both compilers fail to support the standard "out of the box". In my particular case, I was just trying to query the current runtime locale name using C++ as opposed to C, ie instead of set `setlocale(LC_ALL, "")`. – tegtmeye Oct 15 '19 at 14:44