这个使用 <locale> 的简单 C++ 程序是否正确?
Is this simple C++ program using <locale> correct?
此代码似乎在(ubuntu 可信)版本的 gcc 和 clang 中以及通过 mingw 在 VM 上的 Win 7 中工作正常...最近我升级到 Wily 并且使用 clang 构建的构建始终崩溃这里。
#include <iostream>
#include <locale>
#include <string>
int main() {
std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}
有时是乱码字符串,后跟 Aborted: Core dumped
,有时是 invalid free
.
$ ./a.out
The locale is 'en_US.UTF-8QX�у�X�у����0�����P�����\�(��\�(��\�(��h��t�������������y���������ț�ԛ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_UP����`�������������������������p�����������@��������������`�������������p��������������������@��@��@��`��������p������������0��P��p���qp��!en_US.UTF-8QЈ[�����\�(��\�(��\�(�����������@�� �����P�����0�����P�����\�(��\�(��\�(��Ȣ�Ԣ����������������(��4��@��L��en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!�v[��������������@�� �����P�����0�����P�����\�(��\�(���(��h��t��������������������Ȥ�Ԥ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!��[�� ����[�������7����7��.,!!x�[��!��[��!�[��@�����������@�� �����P�����0�����P�����\�(��\�(��\�(��(��4��@��L��X��d��p��|������������n_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻAborted (core dumped)
$ ./a.out
The locale is 'en_US.UTF-8QX\%�QX\%�Q�G�0H��H�PI��I�\:|�Q\D|�Q\>|�QhK�tK��K��K��K��K��Q�K��K��K��K��K��K�en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻ
*** Error in `./a.out': free(): invalid pointer: 0x0000000000b04a98 ***
Aborted (core dumped)
(上面的两个程序输出都被大大简化了,否则它们不适合这个问题。)
我也得到了一个invalid free on Coliru。
但这与 cppreference 上的示例代码非常相似:
#include <iostream>
#include <locale>
#include <string>
int main()
{
std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
// on startup, the global locale is the "C" locale
std::wcout << 1000.01 << '\n';
// replace the C++ global locale as well as the C locale with the user-preferred locale
std::locale::global(std::locale(""));
// use the new global locale for future wide character output
std::wcout.imbue(std::locale());
// output the same number again
std::wcout << 1000.01 << '\n';
}
实际上那个代码 crashes Coliru 也...:facepalm:
这是 clang 使用的 c++ 库中的错误,还是此代码有缺陷?
另请注意:这些崩溃似乎仅限于 C++ api,如果您使用 <clocale>
而不是事情似乎工作正常,所以它可能只是 C++ 绑定中的一些小问题超过这个?
我认为 ""
参数可能损坏了某些东西。我不认为这是一个法律论据?
要验证它不是别的,请尝试运行这个:
#include <iostream>
#include <locale>
int main() {
std::locale("").name();
}
它在 GCC 上编译和运行得很好:
g++ -Wall -pedantic locale.cpp
<= No errorrs, no warnings
./a.out
The locale is 'en_US.UTF-8'
<= Expected output
附录:
与 MSVS 2013 完全相同 - 没有错误或警告编译;没有错误 运行:
locale.cpp =>
#include <iostream>
#include <locale>
#include <string>
int main() {
std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}
输出=>
locale
The locale is 'English_United States.1252'
看起来这是由 libstdc++ 在其 basic_string
中的 ABI 更改引起的,这是 C++11 一致性所必需的。为了管理这种转换,GCC 添加了 abi_tag
属性,它更改了函数的错位名称,以便可以区分新旧 ABI 的函数,即使更改不会以其他方式影响错位名称(例如return 函数类型)。
这个代码
#include <locale>
#include <string>
int main() {
std::locale().name();
}
在 GCC emits a call to _ZNKSt6locale4nameB5cxx11Ev
上,它分解为 std::locale::name[abi:cxx11]() const
,return 是一个带有新 ABI 的 SSO 字符串。
Clang,另一方面,doesn't support the abi_tag
attribute, and emits a call to _ZNKSt6locale4nameEv
,它分解为简单的 std::locale::name() const
- 这是 returning COW 字符串的版本(旧的 ABI ).
最终结果是程序在使用 Clang 编译时最终尝试使用 COW 字符串作为 SSO 字符串。浩劫接踵而至。
明显的解决方法是通过-D_GLIBCXX_USE_CXX11_ABI=0
强制使用旧的 ABI。
此代码似乎在(ubuntu 可信)版本的 gcc 和 clang 中以及通过 mingw 在 VM 上的 Win 7 中工作正常...最近我升级到 Wily 并且使用 clang 构建的构建始终崩溃这里。
#include <iostream>
#include <locale>
#include <string>
int main() {
std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}
有时是乱码字符串,后跟 Aborted: Core dumped
,有时是 invalid free
.
$ ./a.out
The locale is 'en_US.UTF-8QX�у�X�у����0�����P�����\�(��\�(��\�(��h��t�������������y���������ț�ԛ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_UP����`�������������������������p�����������@��������������`�������������p��������������������@��@��@��`��������p������������0��P��p���qp��!en_US.UTF-8QЈ[�����\�(��\�(��\�(�����������@�� �����P�����0�����P�����\�(��\�(��\�(��Ȣ�Ԣ����������������(��4��@��L��en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!�v[��������������@�� �����P�����0�����P�����\�(��\�(���(��h��t��������������������Ȥ�Ԥ�������en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8!��[�� ����[�������7����7��.,!!x�[��!��[��!�[��@�����������@�� �����P�����0�����P�����\�(��\�(��\�(��(��4��@��L��X��d��p��|������������n_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻAborted (core dumped)
$ ./a.out
The locale is 'en_US.UTF-8QX\%�QX\%�Q�G�0H��H�PI��I�\:|�Q\D|�Q\>|�QhK�tK��K��K��K��K��Q�K��K��K��K��K��K�en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8en_US.UTF-8ѻ
*** Error in `./a.out': free(): invalid pointer: 0x0000000000b04a98 ***
Aborted (core dumped)
(上面的两个程序输出都被大大简化了,否则它们不适合这个问题。)
我也得到了一个invalid free on Coliru。
但这与 cppreference 上的示例代码非常相似:
#include <iostream>
#include <locale>
#include <string>
int main()
{
std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
// on startup, the global locale is the "C" locale
std::wcout << 1000.01 << '\n';
// replace the C++ global locale as well as the C locale with the user-preferred locale
std::locale::global(std::locale(""));
// use the new global locale for future wide character output
std::wcout.imbue(std::locale());
// output the same number again
std::wcout << 1000.01 << '\n';
}
实际上那个代码 crashes Coliru 也...:facepalm:
这是 clang 使用的 c++ 库中的错误,还是此代码有缺陷?
另请注意:这些崩溃似乎仅限于 C++ api,如果您使用 <clocale>
而不是事情似乎工作正常,所以它可能只是 C++ 绑定中的一些小问题超过这个?
我认为 ""
参数可能损坏了某些东西。我不认为这是一个法律论据?
要验证它不是别的,请尝试运行这个:
#include <iostream>
#include <locale>
int main() {
std::locale("").name();
}
它在 GCC 上编译和运行得很好:
g++ -Wall -pedantic locale.cpp
<= No errorrs, no warnings
./a.out
The locale is 'en_US.UTF-8'
<= Expected output
附录:
与 MSVS 2013 完全相同 - 没有错误或警告编译;没有错误 运行:
locale.cpp =>
#include <iostream>
#include <locale>
#include <string>
int main() {
std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}
输出=>
locale
The locale is 'English_United States.1252'
看起来这是由 libstdc++ 在其 basic_string
中的 ABI 更改引起的,这是 C++11 一致性所必需的。为了管理这种转换,GCC 添加了 abi_tag
属性,它更改了函数的错位名称,以便可以区分新旧 ABI 的函数,即使更改不会以其他方式影响错位名称(例如return 函数类型)。
这个代码
#include <locale>
#include <string>
int main() {
std::locale().name();
}
在 GCC emits a call to _ZNKSt6locale4nameB5cxx11Ev
上,它分解为 std::locale::name[abi:cxx11]() const
,return 是一个带有新 ABI 的 SSO 字符串。
Clang,另一方面,doesn't support the abi_tag
attribute, and emits a call to _ZNKSt6locale4nameEv
,它分解为简单的 std::locale::name() const
- 这是 returning COW 字符串的版本(旧的 ABI ).
最终结果是程序在使用 Clang 编译时最终尝试使用 COW 字符串作为 SSO 字符串。浩劫接踵而至。
明显的解决方法是通过-D_GLIBCXX_USE_CXX11_ABI=0
强制使用旧的 ABI。