c ++字符串文字仍然令人困惑

时间:2015-05-07 11:31:06

标签: c++ unicode

我一直在阅读一些关于Unicode的文章,并意识到我仍然对此做些什么感到困惑。

作为Windows平台上的c ++程序员,给予我的学科与任何教师大致相同:始终使用Unicode字符集;如果可能的话,将其模板化或使用TCHAR;喜欢wchar_t,std :: wstring over char,std :: string。

#include <tchar.h>
#include <string>
typedef std::basic_string<TCHAR> tstring;
 // ...
static const char* const s_hello = "핼로"; // bad
static const wchar_t* const s_wchar_hello = L"핼로" // better
static LPCTSTR s_tchar_hello = TEXT("핼로") // even better
static const tstring s_tstring_hello( TEXT("핼로") ); // best

不知怎的,我搞砸了,我引导自己相信如果我说“某事”,那就意味着它是ASCII格式的,如果我说L“某事”就是Unicode。然后我读到了这个:

  

类型wchar_t是一种不同的类型,其值可以表示支持的语言环境(22.3.1)中指定的最大扩展字符集的所有成员的不同代码。类型wchar_t应具有与其他整数类型之一相同的大小,符号和对齐要求(3.11),称为其基础类型。类型char16_t和char32_t分别表示与uint_least16_t和uint_least32_t相同的大小,符号和对齐的不同类型,称为基础类型。

那又怎样?如果我的语言环境从代码页949开始,那么wchar_t的扩展是从949 + 2 ^(sizeof(wchar_t)* 8)?它说话的方式听起来像'我不在乎你的c ++实现是使用UTF编码还是'。

至少,我可以理解一切都取决于应用程序所在的语言环境。因此我测试了:

#define TEST_OSTREAM_PRINT(x) \
std::cout << "----" << std::endl; \
std::cout << "cout : " << x << std::endl; \
std::wcout << "wcout : " << L##x << std::endl;

int main()
{
    std::ostream& os = std::cout;

    std::cout << " * Info : " << std::endl
              << "     sizeof(char) : " << sizeof(char) << std::endl
              << "     sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl
              << "     littel endian? : " << IsLittelEndian() << std::endl;
    std::cout << " - LC_ALL: " << setlocale(LC_ALL, NULL) << std::endl;
    std::cout << " - LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << std::endl;

    TEST_OSTREAM_PRINT("핼로");
    TEST_OSTREAM_PRINT("おはよう。");
    TEST_OSTREAM_PRINT("你好");
    TEST_OSTREAM_PRINT("resume");
    TEST_OSTREAM_PRINT("résumé");

    return 0;
}

然后输出是:

Info
 sizeof(char) = 1
 sizeof(wchar_t) = 2
 LC_ALL = C
 LC_CTYPE = C
----
cout : 핼로
wcout : ----
cout : おはよう。
wcout : ----
cout : ?好
wcout : ----
cout : resume
wcout : resume
----
cout : r?sum?
wcout : r?um

使用韩语语言环境的另一个输出:

Info
 sizeof(char) = 1
 sizeof(wchar_t) = 2
 LC_ALL = Korean_Korea.949
 LC_CTYPE = Korean_Korea.949
----
cout : 핼로
wcout : 핼로
----
cout : おはよう。
wcout : おはよう。
----
cout : ?好
wcout : ----
cout : resume
wcout : resume
----
cout : r?sum?
wcout : resume

另一个输出:

Info
 sizeof(char) = 1
 sizeof(wchar_t) = 2
 LC_ALL = fr-FR
 LC_CTYPE = fr-FR
----
cout : CU·I
wcout : ----
cout : ªªªIªeª|¡£
wcout : ----
cout : ?u¿
wcout : ----
cout : resume
wcout : resume
----
cout : r?sum?
wcout : resume

事实证明,如果我没有给出正确的语言环境,那么无论我使用char还是wchar_t,应用程序都无法处理某些范围的字符。这不仅仅是问题。 Visual Studio发出警告:

warning C4566: character represented by universal-character-name '\u4F60' cannot be represented in the current code page (949)

我不确定这是否描述了我输出的内容或其他内容。

问题。什么是最佳实践以及为什么?如何使应用程序平台/实现/国家独立?源上字符串文字究竟发生了什么?应用程序如何解释字符串值?

2 个答案:

答案 0 :(得分:3)

C ++没有正常的Unicode支持。在不使用第三方库的情况下,您无法在C ++中实现全球化的应用程序。阅读this富有洞察力的SO答案。如果你真的需要编写一个使用Unicode的应用程序,请查看ICU库。

答案 1 :(得分:2)

在Windows上,wchar_t支持Unicode的Microsoft guarantees,因此L"핼로"是生成UTF-16字符串文字为const wchar_t*的正确方法。在其他平台上,这不一定成立,如果您需要代码,则应使用C ++ 11 Unicode字符串文字(u8"..."u"..."U"...")便携式 - 例如,使用u8"핼로"生成UTF-8编码的const char*(从Visual Studio 2015开始)。

您遇到的另一个问题是Visual Studio如何解释源文件的编码。例如,在EUC-KR中编码为0xAA 0xAA(代码页949),这是代码页1252(fr-FR)中ªª的编码 - 也就是说,如果您在EUC-KR中保存了包含的源文件,但是在fr-FR语言环境中编译它,您的文字将编码为ªª

如果您需要在源中包含非ASCII字符,则应使用UTF(即UTF-8/16/32)将其保存在answer to this question中描述的明确BOM中。 / p>

相关问题