cout 与 wcout 有何不同
基本概念:
字符集:字符的数字代码集。 有 ANSI/ASCII、MBCS(Multibytes)、Unicode 等。比如“汉”字 Unicode 代码为 0x6c49。
编码方案:记录字符代码的方式。有 UTF-8、UTF-16、GB2312 等。编码方案分“变长编码”与“定长编码”两种。UTF-8 是变长编码
字符集与编码方案概念分明,却互依互存。字符集与编码方案是配套的。比如提到 GB2312 编码,即是指 GB2312 字符集与 GB2312 编码方案。此处 GB2312 为两字节定长编码。而提到 Unicode 编码,即指 Unicode 字符集与 UTF-X 编码方案。其中 UTF-16 为两字节定长编码,UTF-8 设计为变长是为了工业应用中兼容已有的 ANSI/ASCII 编码,并广泛应用于互联网业务。
源码文件与生成的程序文件编码是两回事儿。源码文件编码是文本文件保存时指定的编码;而程序文件编码依赖系统环境设置
常量字串在代码中是用源码文件编码记录的;而编译时将如何处理呢?这就讨论到了 cout 与 wcout 之不同。Win32 中,二者之别等价于变长与定长编码之分,或者说是采用非 UTF-16 还是 UTF-16 之分。自 Win2k 以降,基于 WinNT 内核的 Win OS 已全面更新为 UTF-16 编码。此处 Unicode 仅指Unicode 字符集配 UTF-16 编码。其余,包括 UTF-8、UTF-7、GB2312、ANSI/ASCII 等一律划归 Multibytes。故而 Multibytes 应理解为“变长”字符,而非“多”字符。二者转换,WinApi 提供MultiByteToWideChar 和WideCharToMultiByte 方法。转换的依据是 CodePage。对此,MSDN 上有细目可查。比如 MS936 码页便是 GB2312 与 Unicode 的映射关系表。
MSDN上提供的代码示例(略作修改测试区别):
// iostream_cerr.cpp // compile with: /EHsc // By default, cerr and clog are the same as cout #include <iostream> #include <fstream>
using namespace std;
void TestWide( ) { int i = 0; wcout.imbue ( locale ( "chs" ) ); wcout <<L"Enter a number:"; wcin >> i; wcerr << L"test for wcerr汉字" << endl; wclog << L"test for wclog汉字" << endl; }
int main( ) { int i = 0; cout << "Enter a number汉字: "; cin >> i; cerr << "test for cerr汉字" << endl; clog << "test for clog汉字" << endl; TestWide( ); }
L 将字串转码成 UTF-16 流wcout中,L将 字串转码成 UTF-16 流,没有加 L,编译时按系统默认环境编码。没有:wcout.imbue ( locale ( "chs" ) ); 输出结果
Enter a number汉字: 7
test for cerr汉字
test for clog汉字
Enter a number:7
test for wcerrtest for wclog
有:wcout.imbue ( locale ( "chs" ) );输出结果
Enter a number汉字:9
test for cerr汉字
test for clog汉字
Enter a number:9
test for wcerr汉字
test for wclog汉字
指定了 chs 环境,也即 MS936 CodePage 映射,因此系统将 UTF-16 码流转为 GB2312 码流输出到控制台缓存(控制台为 I/O 终端文件)。