C/C++ 中的字符类型:
signed char | 有符号字符 | |
unsigned char | 无符号字符 | |
char | 根据实现,可以是无符号活有符号 | |
wchar_t | 宽字符 | C95 |
char16_t | UTF-16字符 | C++0x, C1x |
char32_t | UTF-32字符 | C++0x, C1x |
wchar_t
刚接触QString时,一直不明白其内部为何为何不采用wchar_t。
Unicode 4.0标准的5.2节提到:
-
"The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compilershould not use wchar_t for storing Unicode text. The wchar_t type is intended forstoring compiler-defined wide characters, which may be Unicode characters in some compilers."
这样看起来,wchar_t 真不是一个好东西。难怪C、C++的新标准中要引入char16_t和char32_t
两种字符集
-
Two sets of characters and their associated collating sequences shall be defined: the set in which source files are written (the source character set), and the set interpreted in the execution environment (the execution character set).
C、C++标准讨论两种字符集:
source input character set | 源文件的编码 |
execution character set | 字符串被写入到目标(object)文件时的编码 |
新标准引入了char16_t和char32_t两种字符类型,但这只解决了第二个编码问题
const char * s1 = u8"hello utf8 string"; const char16_t * s2 = u"hello utf16 string"; const char32_t * s3 = U"hello utf32 string"; const wchar_t * s4 = L"hello wide string"
第一个依然问题依然没能解决:
- 采用gcc时,可以通过 -finput-charset=gbk 选项告诉编译器源文件的编码(默认utf8?)
- 采用cl时,源文件有BOM,则按照BOM的编码;如果没有,则使用本地的代码页。
真想知道C、C++为什么不能想python一样,在文件开头可以通过对程序无碍的注释来指定源文件的编码信息。
u8使用一则
在Windows下有这么一个问题:
int main() { const char * s = "我是中文"; return 0; }
如果源文件保存成带BOM的utf8,然后分别用MinGW的gcc 和 MSVC的cl进行编译。这个字符串的execution character set将不同,一个是utf8,一个是gb18030。
如果写成u8"我是中文"将可以解决这个问题。
这样一来,当我们在QString中使用中文的时候,不用再纠结使用
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB18030"));
还是使用
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
更重要的一点是,使用了"u8"我们的Qt程序不需要中文的编解码插件了,即使你的源文件是gb18030编码。
而且,Qt正在考虑是否将utf8而不是现在latin1作为QString的默认转换编码,如果实现的话,我们连 setCodecForCStrings 都不需要了(这对喜欢在源码中喜欢用中文的朋友,应该是一个好消息)。
坏消息是:尽管GCC没有问题,但最新的MSVC2010依然还未支持这种写法。
raw string
这是个不错的东西,至少不用老想着转义字符了:
"C://windows//system32" R"(C/windows/system32)"
输入和输出
不同于wchar_t,C++0x标准没有提供 u16cout、u32cout 来输出 char16_t 和 char32_t 的字符串。
不过可以先转换成字节流再输出:c16rtomb、c32rtomb (头文件 uchar.h 或 cuchar)