我一直在阅读关于Unicode的文章,但意识到我仍然不知道该怎么做。
作为Windows平台上的C++程序员,我的老师们教给我的规则大多都是相同的:始终使用Unicode字符集;如果可能的话,使用模板化或TCHAR;优先使用wchar_t、std::wstring而不是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
不知怎么地,我搞混了,我自己认为如果我说“something”,那么它就是ASCII格式,如果我说L“something”,那么它就是Unicode格式。然后我读到这个:
wchar_t类型是一个独特的类型,它的值可以代表所支持语言环境中最大扩展字符集的所有成员的不同代码(22.3.1)。 wchar_t类型应该具有与其他整数类型之一相同的大小、符号和对齐要求(3.11),称为其基础类型。char16_t和char32_t分别表示具有与uint_least16_t和uint_least32_t相同的大小、符号和对齐要求的不同类型,在《C ++标准库》中称为基础类型。
那又怎样呢?如果我的语言环境从代码页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)
我不确定这是否描述了我所获得的输出或其他内容。
问题:什么是最佳实践,为什么?如何使应用程序平台/实现/国家独立?源代码中的字符串文字会发生什么?应用程序如何解释字符串值?
TCHAR
是一个巨大的麻烦。除非你想支持旧版本的Windows,否则只需使用Windows宽字符串。为了与其他内容兼容,您可以使用UTF-8存储字符串,并在使用Windows API函数时进行转换。 - chris