这个简单的C ++程序使用<locale>是否正确?

时间:2015-12-07 01:17:09

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

此代码似乎在(ubuntu可信赖)版本的gcc和clang中正常工作,并且在Win 7上通过mingw在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:

来自Coliru的类似代码的

More crashes

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

另请注意:这些崩溃似乎仅限于C ++ api,如果使用<clocale>而事情似乎工作正常,那么它可能只是C ++绑定中的一些微不足道的问题吗?

使用setlocale的变体:1 2 3

3 个答案:

答案 0 :(得分:6)

看起来这是由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。

答案 1 :(得分:1)

我认为""参数可能会破坏某些内容。我不认为这是一个法律论点吗?

要验证它没有别的,请尝试运行:

#include <iostream>
#include <locale>

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

答案 2 :(得分:1)

它与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 =&gt;

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

int main() {
  std::cout << "The locale is '" << std::locale("").name() << "'" << std::endl;
}

输出=&gt;

locale
The locale is 'English_United States.1252'