`

VC 之 cout 与 wcout 区别及 wchar_t、CharSet、CodePage 等相关概念解析 (转载)

 
阅读更多

VC 之 cout 与 wcout 区别及 wchar_t、CharSet、CodePage 等相关概念解析 (转载)

图一
       实验平台信息见:《测试 VS 2010 对 C++ 0x 标准的谨慎支持》。
       先说两组概念:字符集(CharSet)与编码方案(Encoding Scheme)、源代码文件编码(Source file CharSet)与程

序文件编码(Exec file CharSet)。
       第一组,字符集与编码方案:
       字符集就是字符的数字代码集。有 ANSI/ASCII、MBCS(Multibytes)、Unicode 等。比如“汉”字 Unicode 代码为

0x6c49。
       编码方案就是记录字符代码的方式。有 UTF-8、UTF-16、GB2312 等。编码方案分“变长编码”与“定长编码”两种。

UTF-8 是变长编码,模板如下:
       0x0000 – 0x007F 表一字节 0xxxxxxx
       0x0080 – 0x07FF 表两字节 110xxxxx 10xxxxxx
       0x0800 – 0xFFFF 表三字节 1110xxxx 10xxxxxx 10xxxxxx
       比如 UTF-8 编码序列 11100110 10110001 10001001,由首字节判断为三字节模板,解析时连续读取三字节并将编码模

板去除,剩 0110 110001 001001,连在一起即为 01101100B 01001001B,也即 0x6c49,即“汉”字。
       字符集与编码方案概念分明,却互依互存。字符集与编码方案是配套的。比如提到 GB2312 编码,即是指 GB2312 字符

集与 GB2312 编码方案。此处 GB2312 为两字节定长编码。而提到 Unicode 编码,即指 Unicode 字符集与 UTF-X 编码方案。

其中 UTF-16 为两字节定长编码,UTF-8 设计为变长是为了工业应用中兼容已有的 ANSI/ASCII 编码,并广泛应用于互联网业

务。
       双字节定长编码为了与单字节编码区分,注意到单字节编码最高位为 0,故设定首字节最高位为 1,指示解析器需要连

续读取两字节。
       第二组,源码编码与程序编码:
       源码文件与生成的程序文件编码是两回事儿。源码文件编码是文本文件保存时指定的编码;而程序文件编码依赖系统环

境设置。
       第二组问题的焦点在于“常量字串”的处理上。常量字串在代码中是用源码文件编码记录的;而编译时将如何处理呢?

这就讨论到了 cout 与 wcout 之不同。
________________________________________
       cout 与 wcout 有何不同?图一可见前两行正确显示,后两行显示异常。显示异常当然是因为常量字串处理出了问题。
       再说两组概念:Multibytes 与 Uniocde、Win OS 之 wchar_t 与 ANSI/ISO C/CPP 之 wchar_t。
       第一组、Multibytes 与 Uniocde:
       VC 下,或者说 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 的映射关系表。
       第二组、Win OS 之 wchar_t 与 ANSI/ISO C/CPP 之 wchar_t:
       ANSI/ISO C/CPP 中 wchar_t 表示长于 8-bit 的数据类型,至于多长,具体依赖实现。《Unicode 标准 4.0》如是说


“ANSI/ISO C leaves the semantics of the wide character set to the specific implementation but requires that

the characters from the portable C execution set correspond to their wide character equivalents by zero

extension.”
“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++ compiler should not use wchar_t for storing Unicode text. The wchar_t type is

intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers.”
       标准可没说 wchar_t 表示的一定是 Unicode 编码,GB2312 也应可由 wchar_t 表示。只不过Win32 下 wchar_t 锁定

为 UTF-16,而 Unix-like 通常为 UTF-32。对于亚欧主要文明体的文字,UTF-16 已经足够。
       在 VC 下,常量字串 "" 对应 const char* 型,L"" 对应 const wchar_t* 型。前者用来处理各种 Multibytes;而后

者指定处理 UTF-16。对应的 cout 与 wcout、string 与 wstring、iostream 与 wiostream 等亦如此。
1. "没有,就没有新中国!" 字串,按系统环境默认编码处理,此处为 GB2312。 
2. L"伟大领袖,万岁、万岁、万万岁!" 宽字串,由于指定了 L,因此该字串将转成 UTF-16 码流传给 wcout。

注意其上一行指定了 chs 环境,也即 MS936 CodePage 映射,因此系统将 UTF-16 码流转为 GB2312 码流输出到控制台缓存(

控制台为 I/O 终端文件)。
3. "Let's Fuck 亚米利加合众国!" 字串,系统将传给 wcout 的系统默认编码流误当成 UTF-16 码去解码为 GB2312,

由于英文字符二者对应,显示正常,而汉字编码不对应,造成汉字显示异常。
4. L"USA Idiot" 宽字串的显示问题则与编码无关,cout 的 << 算符重载不认识 const wchar_t* 型数据,因此将此操

作误当成取址输出,输出的便是该常量字串的地址。
       最后一个问题,工程属性可以设置字符集为 Multibytes 或 Unicode。这是用来切换 Winapi 版本的,是用 Ansi 版本

或 Unicode 版本。
________________________________________
       W 系列流操作对像有何用呢?使用 wcout 比 cout 优势在哪儿呢?见如下例:

图二
       生成一个按倭文编码保存的文件 e:/Fck.txt。然后将那句歌词在控制台上显示出来。已知系统默认环境为 GB2312 编

码。因此通过 w 系列流操作对像,通过 932、936 两页码映射,以 Unicode 流为中介,将 shift_jis 码流转成 gb2312 码流

,在控制台终端正常显示。这活儿,用 cout 办不到。
       那 cout 不就没用了么?可以废掉它了。不!见如下示例:
1. wcout.imbue ( locale ( "chs" ) );
2. wcout << L"打倒美帝国主义!" << endl;
3. // 第四行是另一个程序,与前两行无关,不受第一行约束
4. wcout << "打倒苏修正主义!" << endl;
       第 2 行代码一句输出,首先 L 将字串转码成 UTF-16 流,然后向控制台输出时,还要根据 wcout.imbue 方法指定映

射再转码一次。第 4 行,没有加 L,编译时按系统默认环境编码传给 wcout,但此时,wcout 会误将之用做 UTF-16 码流。尽

管直接输出给控制台,由于未指定映射,码流被原封不动地冲入缓存,由于前后均为系统默认环境编码,因此显示正常;但此

用法是极为危险的,因为其它使用 wcout 对像做转码操作将会失败。
       对于不需要跨文字系统平台的应用来说,使用 wiostream 多此一举,iostream 即可,比如自产自销的本机应用。若考

虑到国际化,则应全部使用 w 系列流操作对像。MSDN 鼓励使用 wiostream。

 

分享到:
评论

相关推荐

    [C++]简单实用的字符转换类

    简单的wchar_t 和 char 转换类, 且包含与UTF8的转换 可调用iconv库,或者VC的API char(ansi) &lt;-&gt; wchar_t(unicode) char(ansi) &lt;-&gt; char(utf8) char(utf8) &lt;-&gt; wchar_t(unicode) 用法: std::cout (src, E_CHAR, ...

    简单实用的字符转换类CWCharToChar

    简单的wchar_t 和 char 转换类, 且包含与UTF8的转换 可调用iconv库,或者VC的API 用法: std::cout (wsrc, EChar).Char(); std::cout (src, EChar, EWChar).WChar(); std::cout (src, EChar, EUtf8).UTF8();

    _cout_163debug.rar_sehuse

    Debug.x:封装SEH 作用:在程序发生未处理的异常时,利用SEH获得异常时刻的信息,并将信息显示或存储到文件。 相关:pe文件操作 Stack操作

    C++控制台小游戏:2048(精致版)

    在某些操作系统上,直接用 cout 或 printf 会导致中文乱码,我只好又用 wchar_t 类型写了一个。 如果此程序您的电脑上乱码了,请用 wchar_t 版。 (wchar_t 类型会引起语法检测的报错,但可以通过编译) 其中数字...

    C++自学实用资料,非常全面

    在C++中还增加了bool型变量和wchar_t型变量: 布尔型变量是有两种逻辑状态的变量,它包含两个值:真和假。如果在表达式中使用了布尔型变量,那么将根据变量值的真假而赋予整型值1或0。要把一个整型变量转换成布尔型...

    STM32F1-ADS1256+SCH.zip

    uint32_t adc_cout[ADS1256_CHANNEL_NUM]; int32_t adc_result[ADS1256_CHANNEL_NUM]; /* ADC Conversion value */ int32_t voltage_uv[ADS1256_CHANNEL_NUM]; /* channel voltage*/ }ads125x_channel_...

    浅谈int8_t int64_t size_t ssize_t的相关问题(详解)

    下面小编就为大家带来一篇浅谈int8_t int64_t size_t ssize_t的相关问题(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    02_cin_cout_oct_hex.cpp

    02_cin_cout_oct_hex.cpp

    VC_Logger VC_LoggerDll

    (注:VC-Logger v2.0.3 依赖 vc-common-src-2.3.2 中的基础公共代码。因此,编译 VC-Logger v2.0.3 时需要同时下载 vc-common-src-2.2.2) /*******************************************************************...

    cin与cout的用法

    cin与cout的用法

    闯城堡游戏

    cout|________________|_____|_______________|\n"; cout欢迎你的到来!\n"; cout; cout请选择难易程度。\n"; cout; cout(1):简单\n"; cout(2):一般\n"; cout(3):困难\n"; cas.choice(); system("PAUSE");...

    cin与cout用法

    本文件是对cin和cout一些用法的总结,框图结构,需要用mindjet打开,(同时推介一下mindjet这款工具,很适合代码爱好者总结)。对cin、cout用法迷惑的请进

    f_cout.rar_quartus_quartus十六进制

    基于Quartus II的8位十六进制频率计的项目设计,包含了项目文件和VHDL源代码

    新版EditLog,重定向cout内容到CEdit窗口

    重定向cout内容到CEdit窗口,新版本EditLog支持VC++2010; 旧版信息 /*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \ editlog.h, Fast asynchronous text logging using a ...

    一个学校学生管理系统源码

    管理系统源码 #include #define N 20 using namespace std; struct student{ int number; int age;...cout姓名** ***********学号 ***班";...cout;...cout&lt;&lt;" ________________________________";...cout**

    各种排序算法

    cout&lt;&lt;"nonsorted_array"; print_array(array,10); //cout&lt;&lt;"select_sort"; //select_sort(array,10); //cout&lt;&lt;"bubble_sort"; //bubble_sort(array,10); //cout&lt;&lt;"insert_sort"; //insert_sort(array,10...

    ncout高阶格式化操作

    这篇文章主要讲解如何在C++中使用cin/cout进行高级的格式化输出操作,包括数字的各种计数法(精度)输出,左或右对齐,大小写等等。通过本文,您可以完全脱离scanf/printf,仅使用cin/cout来完成一切需要的格式化...

    cout不打印,不显示,不输出 怎么办?

    解决cout不显示,不输出,不打印

    C++银行自动取款机统

    cout &lt;&lt; "\t\t请选择您要办理的手续:\n"; cout &lt;&lt; "\t\t\t\t1.存款\n"; cout &lt;&lt; "\t\t\t\t2.取款\n"; cout &lt;&lt; "\t\t\t\t3.查询余额\n"; cout &lt;&lt; "\t\t\t\t4.转账\n"; cout &lt;&lt; "\t\t\t\t5.更改密码\n"; cout ...

    MingW VC 之.a .lib .dll .def 关系

    MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe) 玩转攻略手记 一份粗糙的研究记录,有待补完和整理。 MinGW: c -&gt; o gcc -c a.c c -&gt; exe gcc a.c libs.o -o a.exe (从主程序a.c,附加libs,生成a.exe) o -...

Global site tag (gtag.js) - Google Analytics