【问题标题】:Is this simple C++ program using <locale> correct?这个使用 <locale> 的简单 C++ 程序是否正确?
【发布时间】:2015-12-07 01:17:08
【问题描述】:

此代码似乎在 gcc 和 clang 的(ubuntu 可信赖的)版本中以及通过 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:

Morecrashes 来自 Coliru 的类似代码。

这是clang使用的c++库的bug,还是这段代码有缺陷?

另请注意:这些崩溃似乎仅限于 C++ api,如果您使用 &lt;clocale&gt;,则一切似乎都可以正常工作,所以这可能只是 C++ 绑定中的一些琐碎问题?

使用setlocale的变体:123

【问题讨论】:

  • 在我看来很明显像一个错误。您是否考虑过询问 clang 邮件列表和/或将其报告为错误?似乎是一个更合适的地方问...
  • 如果编译器clang编译这段代码时崩溃了,那么这是一个clang错误,应该报告。
  • @LightnessRacesinOrbit:是的,我想这是下一步
  • 好吧,如果改用&lt;clocale&gt; 并使用表达式setlocale(LC_ALL, NULL),那么它似乎工作正常......所以这似乎很空洞并且很容易解决。跨度>
  • 在 coliru 上,只需 int main() { std::locale().name(); }(包含正确的包含)给出相同的免费错误

标签: c++ c++11 clang locale


【解决方案1】:

看起来这是由 libstdc++ 的 basic_string 中的 ABI 更改引起的,这是 C++11 一致性所必需的。为了管理这种转换,GCC 添加了 abi_tag 属性,它更改了函数的重命名,以便可以区分新旧 ABI 的函数,即使更改不会影响重命名的名称(例如返回类型函数)。

这段代码

#include <locale>
#include <string>

int main() {
   std::locale().name();
}

在 GCC emits a call to _ZNKSt6locale4nameB5cxx11Ev 上,它与 std::locale::name[abi:cxx11]() const 解耦,并返回带有新 ABI 的 SSO 字符串。

另一方面,Clang 是 doesn't support the abi_tag attributeemits a call to _ZNKSt6locale4nameEv,它们分解为简单的 std::locale::name() const - 这是返回 COW 字符串的版本(旧 ABI)。

最终结果是,当使用 Clang 编译时,程序最终会尝试使用 COW 字符串作为 SSO 字符串。破坏随之而来。

显而易见的解决方法是通过 -D_GLIBCXX_USE_CXX11_ABI=0 强制使用旧 ABI。

【讨论】:

【解决方案2】:

我认为"" 参数可能会破坏某些东西。我不认为这是一个法律论据?

要验证它是不是别的,请尝试运行:

#include <iostream>
#include <locale>

int main() {
    std::locale("").name();
}

【讨论】:

  • 这应该是一条评论。
【解决方案3】:

它可以用 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'

【讨论】:

    猜你喜欢
    • 2018-01-31
    • 1970-01-01
    • 2012-11-02
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多