Windows平台字符的存储和输出分析
1. 引言
(写于2011-07-30)
在Windows NT系列的操作系统中最常用的两种字符集是ANSI和Unicode。ANSI是一种泛称,每一个国家或地区的ANSI编码都不一样,比如在Windows XP简体中文版中,ANSI的编码为GBK,而在Windows XP日文版中ANSI的编码是JIS。Unicode的全称是Universal Multiple-Octet Coded Character Set,中文含义是“通用多八位编码字符集”。Unicode的目标是为世界是所有的字符提供一套唯一的、统一的字符编码,所以不管理在作保地方任何操作系统,一个确定字符的编码都是唯一的。由于Unicode采用大于等于2个字节来储存字符编码,所以有可能在不同的操作系统中储存的字节顺序不一样,可分为大端方式和小端方式。
存储方式
以“中文”两个汉字举例说明,在Windows XP简体中文版中,“中文”两个字的ANSI/GBK和Unicode分别为:
|
字符 |
中 |
文 |
|
ANSI/GBK |
0XD6D0 |
0XCEC4 |
|
Unicode |
0X4E2D |
0X6587 |
2. 内存中的储存方式
在VC中,定义字符有两种方式:char类型和wchar_t类型。char类型采用ANSI/GBK编码,而wchar_t采用Unicode编码,wchar_t也是常说的宽字符型。
定义如下两个字符串
char* str = "中文";
wchar_t* wcstr = L"中文";
通过调试我们可以看到这两个字符串在内存中的储存方式。编译后,指针str所指向的地址为0x004188CC,“中文”两个字在内存中的表示方式为:d6 d0 ce c4,刚好是“中文”两个字的GBK码,从而可知,如一个字符串在VC中被定义为char*类型,那么字符将被编为ANSI/GBK码,如图 1所示。

图 1 “中文”在内存中的ANSI编码
wchar_t类型指针wcstr所指向的地址为0x004188C4,如图 2所示。从图可知,在VC中,wchar_t类型的字符串将被编译为Unicode码,并按UTF-16小端方式储存。

图 2 “中文”在内存中的Unicode编码
Unicode只规定了字符的编码,没有规定如何储存这些编码。储存Unicode码常用三种方式:
1、UTF-16小端方式:用两个字节储存Unicode码,低字节在前,高字节在后;
2、UTF-16大端方式:用两个字节储存Unicode码,高字节在前,低字节在后;
3、UTF-8:用1~4个字节按一定规则存放Unicode码,汉字需要用3个字节。
图 2中的“2d4e8765”正是“中文”两个汉字的Unicode码“4e2d6587”按UTF-16小端方式储存。
3. 磁盘中的储存方式
打开Windows记事本,输入“中文”两个字,在另存为对话框中的编码下拉框中分别选择ANSI、Unicode、Unicode big endian和UTF-8储存为四个文本文件,然后用十六进制文本编辑器打开,内容如下表
表 1
|
编码 |
十六进制内容 |
|
ANSI |
D6 D0 CE C4 |
|
Unicode |
FF FE 2D 4E 87 65 |
|
Unicode big endian |
FE FF 4E 2D 65 87 |
|
UTF-8 |
EF BB BF E4 B8 AD E6 96 87 |
从表中可以看出,对于选择ANSI编码,会采用系统默认编码按大端方式直接储存,对于Windows XP简体中文版,系统默认编码是GBK,所以文件中储存的内容就是“中文”两个字的的GBK编码D6 D0 CE C4。
如果是Unicode编码,按照规定,要在文件的开头加上一个“ZERO WIDTH NO-BREAK SPACE”标识,可直译为“零宽度非换行空格”,目标是标识文件是以哪一种方式来储存Unicode码。“中文”的Unicode码为“4E2D 6587”常用三种方式储存
表 2
|
储存方式 |
字符串编码内容 |
|
UTF-16 Little Endian (小端) |
2D4E 8765 |
|
UTF-16 Big Endian (大端) |
4E2D 6587 |
|
UTF-8 |
E4B8AD E69687 |
注:UTF-8是变长的,储存一个字母要一个字节,一个汉字要三个字节;UTF-16是定长的,不管是储存一个字母还是一个汉字都需要两个字节,所以用UTF-16储存字母时会造成空间浪费。
这三种储存方式所对应的标识为
表 3
|
储存方式 |
对应的标识 |
|
UTF-16 Little Endian (小端) |
FF FE |
|
UTF-16 Big Endian (大端) |
FE FF |
|
UTF-8 |
EF BB BF |
所以从表 1 可知,
1、 如果选择“Unicode”,会将字符串编译为Unicode码,按UTF-16小端方式储存;
2、 如果选择“Unicode big endian”,会将字符串编译为Unicode码,按UTF-16大端方式储存;
3、 如果选择“UTF-8”,会将字符串编译为Unicode码,按UTF-8方式储存。
从上面我们也可知道,如果一个文本文件的前两个字节是“FFFE”,那么这个文件一定是按小端方式储存字符的Unicode码,第三个字节是Unicode码的低字节,第四个字节是Unicode码的高字节,根据这两个高低字节就可以得出一个Unicode字符。第五个字节是第二个字符的Unicode码的低字节,第六个字节是第二个字符的Unicode码的高字节。
UTF-8码是将字符的Unicode码按一定规则存放到1~4个字节中,根据UFT-8码也可以得出字符的Unicode码,请别参考其他文档。
4. 字符的输出方式
知道字符在计算机如何编码,如何储存后,那么如何将这些输出呢?
4.1 Windows控制台的输出方式
Widows在内部维护了一块控制台输出缓冲区,如要要向控制台输出字符串,只要将字符串所对应的内存区域复制到控制台缓冲区,Windows就会以默认的字符编码将控制台缓冲区的内容输出到控制台窗口。对于Windows XP简体中文版,默认的字符编码是GBK,所以Windows会以GBK码的方式输出控制台缓冲区的内容。要想Windows XP简体中文版的控制台窗口能正确输出控制缓冲区的内容,那么必须保证复制到控制台缓冲区的字符编码是GBK码。
4.2 C/C++中将字符串输出到控制台
对于C语言的printf()函数和C++语言中的std::cout对象,其实都是调用系统“kernel32.dll”中的WriteConsole()函数,将字符串所对应的内存区域复制到控制台的缓冲区。
对于char*类型的字符串,C语言提供的输出函数是printf(),对于wchar_t*类型的字符串,C语言提供的输出函数是wprintf()。
在VC中,char*类型的字符被编译为ANSI(GBK)码,正好和输出缓冲区的编码类型一致,所以可以直接输出。对于wchar_t*类型字符串,VC在编译程序时,会将字符串编译为Unicode码,如果程序运行时,直接将字符串对应的内存区域复制到输出缓冲区,由于字符串的编码和控制台的默认编码不至,控制台将Unicode码当作GBK码输出到控制台时就会出现乱情况。
一个可行的办法是先将Unicode码转换成GBK码,然后再复制到控制台的输出缓冲区,这样就不会出现乱码的问题。
在C语言和C++语言中输出char*类型和wchar_t*类型的字符串
//C语言输出char*类型的字符串(ANSI/GBK) void cprintchar(const char* str)
{
printf("%s\n",str);
} //C语言输出wchar_t*类型的字符串(Unicode)
void cprintwchar(const wchar_t* wcstr)
{
//告诉程序控制台缓冲区使用哪种编码
//<locale.h>
setlocale(LC_ALL,"ZHI");
wprintf(L"%ls\n",wcstr);
} //C++语言输出char*类型字符串(ANSI/GBK)
void ccprintchar(const char* str)
{
std::cout << str << std::endl;
} //C++语言输出wchar_t*类型字符串(Unicode)
void ccprintwchar(const wchar_t* wcstr)
{
//告诉程序控制台缓冲区使用哪种编码
//需要<locale>
std::wcout.imbue(std::locale("ZHI"));
std::wcout << wcstr << std::endl;
}
Windows平台字符的存储和输出分析的更多相关文章
- 转:浅析windows下字符集和文件编码存储/utf8/gbk
最近老猿在学习文件操作及网络爬虫相关知识,发现字符集及编码的处理非常重要,而老猿原来对此了解并不多,因此找了几篇文章看了一下,将老猿认为比较的相关文章转载一下.感谢各位原创大神! 1,字符集 这里主要 ...
- Windows平台下源码分析工具
最近这段时间在阅读 RTKLIB的源代码,目前是将 pntpos.c文件的部分看完了,准备写一份文档记录下这些代码的用处.处理过程.理论公式来源.注意事项,自己还没有弄明白的地方.目前的想法是把每一个 ...
- 认识二进制安全与漏洞攻防技术 (Windows平台)
二进制漏洞是指程序存在安全缺陷,导致攻击者恶意构造的数据(如Shellcode)进入程序相关处理代码时,改变程序原定的执行流程,从而实现破坏或获取超出原有的权限. 0Day漏洞 在计算机领域中,0da ...
- cocos2d-x 开头配置(Windows 平台)
工欲善其事,必先利其器. 要使用 cocos2d-x 引擎,就要配置(或者安装)引擎,到 cocos2d-x 官网下载页下载引擎,官网给了2.x和3.x两个版本,我使用的是3.6的版本,3.x的版本类 ...
- Windows平台配置Appium+Java环境
1) 安装JDK 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装 ...
- Windbg是windows平台上强大的调试器
基础调试命令 - .dump/.dumpcap/.writemem/!runaway Windbg是windows平台上强大的调试器,它相对于其他常见的IDE集成的调试器有几个重要的优势, Windb ...
- 转:Windows平台配置Appium+Java环境
1) 安装JDK 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装 ...
- 不同WINDOWS平台下磁盘逻辑扇区的直接读写
不同WINDOWS平台下磁盘逻辑扇区的直接读写 关键字:VWIN32.中断.DeviceIoControl 一.概述 在DOS操作系统下,通过BIOS的INT13.DOS的INT25(绝对读).INT ...
- MySQL 在Windows平台上的安装及实例多开
MySQL在Windows平台上的安装及实例多开 by:授客 QQ:1033553122 测试环境 Win7 64 mysql-5.7.20-winx64.zip 下载地址: https://cd ...
随机推荐
- CSS Hacks 总结
CSS hack由于不同的浏览器,对CSS的解析认识不一样,因此会导致生成的页面效果不一样,我们就需要针对不同的浏览器去写不同的CSS,让他能在不同的浏览器中也能得到我们想要的页面效果. CSS ha ...
- php给一张图片加上水印效果
<?php /** * 功能:给一张图片加上水印效果 * $i 要加水印效果的图片 * $t 水印文字 * $size 文字大小 * $pos 水印的位置 * $color 文字的颜色 * $f ...
- UVA1589 Xiangqi
Xiangqi is one of the most popular two-player board games in China. The game represents a battle bet ...
- 64位Ubuntu14.04搭建ADT开发环境
本来放假是要出去玩的,结果出游计划拖到了周一,今天先来无事看看ubuntu最近发展得怎么样了,顺便把ADT也搭建好,方便以后研究android框架.想想在windows下,ADT直接down下来解压就 ...
- NOD32强制卸载工具使用方法【转】
装了ESET NOD32又忘记密码了,无法卸载,怎么办? 以下转自官网:http://faq.eset.com.cn/index.php?pid=254 [适用产品:ESET NOD32 防病毒软件4 ...
- 收集点小文,讲CGI,FASTCGI,PHP-CGI,PHP-FPM之间通透点的文章
http://blog.csdn.net/meegomeego/article/details/36180343 http://www.opsers.org/linux-home/server/php ...
- WPF用样式实现TextBox的虚拟提示效果
[版权声明]本文为博主原创,未经允许禁止用作商业用途,如有转载请注明出处. 话说好多软件和网站都能实现虚拟提示,好吧这个名词是我自己起的,因为我也不知道这么形容这个效果. 效果描述:在TextBox没 ...
- 把C#程序(含多个Dll)合并打包成单一文件
实现的方式有多种. 1 Mono 项目中有一个工具,mono的一个附属工具mkbundle.(在Xamarin未被收购开源前,它是加密的商业软件.http://www.cnblogs.com/bins ...
- Android-PullToRefresh 使用心得
目前下拉刷新已经满大街都是,在自己的应用如果不使用这个模式的话,出门都不好意思和人家打招呼,该文章就是简单探讨下针对于 github 上的这个开源项目的使用心得. 为什么是它?因为在 stackove ...
- sort详解
一. 简介 sort命令是帮我们依据不同的数据类型进行排序. 二. 语法 sort [-bcfMnrtk][源文件][-o 输出文件] 补充说明:sort可针对文本文件的内容,以行为单位来排序(默认为 ...