为什么 std::locale("").name() 在 clang 和 gcc 上给出不同的结果?
Why does std::locale("").name() give different results on clang and gcc?
在我的机器 (MacOS 10.14.x) 上编译和 运行 以下代码导致在 clang++ 上打印空字符串并在 g++ 上引发运行时错误。为什么?
#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.
目前,我认为这不是 MacOS 问题,因为 运行 cppreference.com 上的示例也产生了不同的结果。
您可以在以下位置针对不同的编译器版本自行尝试:https://en.cppreference.com/w/cpp/locale/locale/name
在任何情况下,它都不会报告相同的内容:
#include <locale>
#include <iostream>
#include <string>
int main()
{
std::cout << "User-preferred locale setting is "
<< setlocale(LC_ALL, "") << "\n";
return 0;
}
returns 两个编译器的结果相同 ("en_US.UTF-8")。
我错过了什么?
差异可能是因为 clang++ 使用 libc++
而 g++ 使用 libstdc++
。函数 std::locale()
在其中任何一个中定义,并且实现不同。
您可以使用 strace
(如果可用)进行检查,如下所示:
$ strace -e file ./a.out
...
open("/usr/lib/.../libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
...
在此示例中,使用 libstdc++
。
你是对的 "The set of valid string argument values is "C", "", 以及任何实现定义的值..."
但是,如果您尝试设置为未知本地(可能由 local("") 返回),它将抛出 运行-time 错误。
看看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
函数是罪魁祸首。它是一个 C 函数,它将处理传递给它的值的转换。
在 MAC-OS 上 libstdc++
似乎没有正确处理 "" 值,甚至在很多语言环境中都出现了很多问题。
这是 libstdc++(由 g++ 使用)中的一个众所周知的问题。您可以在多个地方轻松找到它,bug report 1,bug report 2, example 1。如您所见,目前 libstdc++ 仅支持 "C" 语言环境。
我说用ICU :)
在我的机器 (MacOS 10.14.x) 上编译和 运行 以下代码导致在 clang++ 上打印空字符串并在 g++ 上引发运行时错误。为什么?
#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.
目前,我认为这不是 MacOS 问题,因为 运行 cppreference.com 上的示例也产生了不同的结果。
您可以在以下位置针对不同的编译器版本自行尝试:https://en.cppreference.com/w/cpp/locale/locale/name
在任何情况下,它都不会报告相同的内容:
#include <locale>
#include <iostream>
#include <string>
int main()
{
std::cout << "User-preferred locale setting is "
<< setlocale(LC_ALL, "") << "\n";
return 0;
}
returns 两个编译器的结果相同 ("en_US.UTF-8")。
我错过了什么?
差异可能是因为 clang++ 使用 libc++
而 g++ 使用 libstdc++
。函数 std::locale()
在其中任何一个中定义,并且实现不同。
您可以使用 strace
(如果可用)进行检查,如下所示:
$ strace -e file ./a.out
...
open("/usr/lib/.../libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
...
在此示例中,使用 libstdc++
。
你是对的 "The set of valid string argument values is "C", "", 以及任何实现定义的值..." 但是,如果您尝试设置为未知本地(可能由 local("") 返回),它将抛出 运行-time 错误。
看看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
函数是罪魁祸首。它是一个 C 函数,它将处理传递给它的值的转换。
在 MAC-OS 上 libstdc++
似乎没有正确处理 "" 值,甚至在很多语言环境中都出现了很多问题。
这是 libstdc++(由 g++ 使用)中的一个众所周知的问题。您可以在多个地方轻松找到它,bug report 1,bug report 2, example 1。如您所见,目前 libstdc++ 仅支持 "C" 语言环境。
我说用ICU :)