我想用C ++编写一个适用于Unix和Windows的程序。该程序应该能够同时使用:Unicode和非Unicode环境。其行为应仅取决于环境设置。
我想要的一个很好的功能是操作从目录中读取的文件名。这些可以是unicode ......或者不是。
实现这一目标的最简单方法是什么?
答案 0 :(得分:9)
我想用C ++编写一个程序 应该适用于Unix和Windows。
首先,确保您了解Unix如何支持Unicode以及Windows如何支持Unicode之间的区别。
在Unicode之前的日子里,两个平台的相似之处在于每个语言环境都有自己的首选字符编码。字符串是char
的数组。一个char
=一个字符,除了少数使用双字节编码的东亚语言环境(由于非自同步而难以处理)。
但他们以两种不同的方式接近Unicode。
Windows NT在早期使用Unicode时,Unicode的目标是固定宽度的16位字符编码。 Microsoft使用16位字符(wchar_t
)而不是8位字符编写了一个全新版本的Windows API。为了向后兼容,他们保留旧的“ANSI”API并定义了大量的宏,因此您可以调用“ANSI”或“Unicode”版本,具体取决于是否定义了_UNICODE
。
在Unix世界(特别是贝尔实验室的Plan 9)中,开发人员认为扩展Unix现有的东亚多字节字符支持以处理3字节字符会更容易,并创建现在称为UTF-的编码8。近年来,类Unix系统一直将UTF-8作为大多数语言环境的默认编码。
Windows理论上可以扩展其ANSI支持以包括UTF-8,但是they still haven't,因为关于字符最大大小的硬编码假设。因此,在Windows上,您会遇到不支持UTF-8的OS API和不支持UTF-8的C ++运行时库。
这样做的结果是:
这为跨平台代码创造了与听起来一样多的复杂性。如果您只是选择一个Unicode编码并坚持下去,就会更容易。
请参阅UTF-8 or UTF-16 or UTF-32 or UCS-2
总结:
是标准C ++“宽字符”类型。但它的编码并不是标准化的:它在Windows上是UTF-16,在Unix上是UTF-32。除了那些使用语言环境依赖 wchar_t
编码作为东亚编程遗产的平台之外。
如果要使用UTF-32,请使用uint32_t
或等效的typedef来存储字符。如果已定义wchar_t
并__STDC_ISO_10646__
,则使用uint32_t
。
新的C ++标准将有char16_t
和char32_t
,这有望消除对如何表示UTF-16和UTF-32的困惑。
是定义wchar_t
时_UNICODE
(假设为UTF-16)的Windows typedef,否则为char
(假设为“ANSI”)。它旨在处理上面提到的重载Windows API。
在my opinion中,TCHAR
很糟糕。它结合了依赖于平台的char
的缺点和依赖于平台的wchar_t
的缺点。避免它。
字符编码是关于信息交换的。这就是“II”代表ASCII的含义。你的程序不存在于真空中。您必须读取和写入文件,这些文件更可能以UTF-8编码而不是UTF-16编码。
另一方面,您可能正在使用使用UTF-16(或更少见的UTF-32)字符的库。在Windows上尤其如此。
我的建议是使用最小化转换量的编码格式。
这个程序应该可以使用 两者:Unicode和非Unicode 环境
最好让你的程序在内部完全使用Unicode,并且只处理遗留编码以读取遗留数据(或编写遗留数据,但如果明确要求则仅 。)
答案 1 :(得分:2)
您必须决定如何在内部代表文字 无论你选择什么,这都应该是不变的。
然后,无论何时读取任何输入,您都必须从输入格式转码为内部格式。然后从内部格式到输出格式的出路。如果您碰巧在内部和外部使用相同的格式,则会成为身份操作。
UTF-8非常适合存储和传输,因为它压缩得很好 但我不喜欢它作为内部表示,因为它具有可变长度。
UTF-16:应该是全人类的救世主 但很快就被UTF-32 所取代UTF-32:修正了。因此非常适合内部表征和操纵 易于转换为UTF-8或从UTF-8转换 非常笨重(每个字符需要4个字节)。
大多数操作系统已经转换为UTF字符串表示形式或正在朝这个方向发展。因此,在ISO-8859内部使用onld obsolte格式只是意味着调用操作系统将导致额外的工作,因为字符串转换为/从UTF转换。结果这似乎是浪费时间(对我而言)。
答案 2 :(得分:1)
您必须决定使用哪种Unicode编码,例如UTF-8,ISO-8859-1等 那么你应该在你的C ++中考虑所有的字符串操作。例如。看看w_char和wstring。 在非Unicode环境中,我假设您的意思是输入变量只是ascii?
答案 3 :(得分:1)
“”(“空字符串”)的区域设置标识符指定特定于实现的默认区域设置。因此,如果将全局语言环境设置为std::locale("")
,那么理论上,您将获得基于环境的语言环境设置初始化的默认语言环境。这与标准c ++给你的帮助差不多。
这在Windows上有一些主要限制,其中MSVC不会使用UTF-8编码提供任何std :: locale。并且Mac OS X不提供除文化中立的“C”语言环境之外的任何std :: locale。
在实践中,在应用程序内部的任何地方标准化UTF-8编码的std :: string是很常见的。然后,在需要与操作系统交互的特定情况下,根据需要进行代码转换。例如,您将使用以UTF-8编码的const char *在unix上定义文件名,但使用UTF-16编码的wchar *在Windows上定义文件名。
UTF-8是一种广泛推荐的内部字符集,适用于可移植的应用程序。 UTF-16具有与UTF-8相同的可变宽度编码问题,并且为许多语言使用更多空间。此外,UTF-16增加了字节顺序问题,并且对unix的支持相对较少。 UTF-32是最简单的编码,但它也使用最多的空间,并且在Windows上没有本机支持。
答案 4 :(得分:1)
就个人而言,我会走另一条路。
无论您选择何种格式,它都应该适应Unicode,这是给定的。但是,您当然不必限制使用现有编码。
特定的编码意味着可以轻松进行通信,但是由于Unix默认为UTF-8,Windows默认为UTF-16,因此无法进行通用编码。因此,我建议您使用自己的内部表示,并根据您定位的操作系统应用合适的转换。这是因为你需要的功能的通用接口和每个OS /编码的实现。
另请注意,无论您使用何种平台,您都应该能够动态更改编码/解码(例如,您可能会要求在Unix上使用UTF-32作为特定文件),另一个原因是使用给定的编码。
总结一下:
ICU
很棒转换可能看似“计算机密集型”,但是:
我的2 cts,正如他们所说:)
答案 5 :(得分:0)
我见过的最好方法是根据条件编译定义typedef
和很少的宏。例如:
#ifdef UNICODE
#define mychar wchar_t
#define s(a) L ## a
typedef std::wstring mystringa;
#else
#define mychar char
#define s(a) a
typedef std::string mystringa;
#endif
typedef std::basic_string<mychar> mystringb;
等等。然后,您可以将字符串用作s("foo")
和mystringa(s("foo"));
。我已经展示了两种创建字符串类型的方法。要么应该工作。