ascii编码与unicode编码
ascii编码与unicode编码
01
ascii编码
定义字符数组 szHello ,初值为 "Hello"。编写程序1:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
char szHello[] = "Hello";
printf("%s\r\n", szHello);
system("pause");
return 0;
}
按 F10 进行单步调试,发现 Hello 字符串的每个字符在内存中各占一个字节,这就是 ascii码 。由美国人发明,所以只出现大小写英文字母、数字和一些符号。因此,最早只有127个字符被编码到计算机里,也就是 7位 2进制数字,最高位(第八位)为 0 。
这个编码表被称为 ascii编码,比如大写字母 H 的编码是 72(16进制48),小写字母 o 的编码是 111(16进制6F)。
02
unicode编码
定义字符数组 szHello ,初值为 "Hello同学们"。编写程序2:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
char szHello[] = "Hello同学们";
printf("%s\r\n", szHello);
system("pause");
return 0;
}
按 F10 进行单步调试,发现字符串 "Hello" 的每个字符在内存中仍各占一个字节,但是字符串 "同学们",每一个汉子在内存中却占两个字节。
这是因为,在中国1990年出版的《辞海》就高达14872个汉字,上面提到的 ascii编码,每个字只用一个字节表示,最多可表示 256 个字,显然是远远不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。
可以想得到的是,全世界有上百种语言,日本,韩国等,并且各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,unicode编码应运而生。unicode编码在内存中占两个字节,最多可表示 65535 个字,可以把所有语言都统一到一套编码里,这样就解决了乱码问题。
通过调试结果也可以看出,字节值为正数,用 ascii 编码表示英文;字节值负数,用 unicode 编码表示中文。
编译执行,并不会出现乱码输出。
03
程序使用unicode编码
但是如果在英文中文混用的情况下,编译器判断一个字节出错时,会连续判断错误,造成大面积的乱码。例如将 6F 改为 8F,如下图所示,导致"同学们"字符串均发生乱码。
因为中英文混用时,内存中一会占一个字节,一会占两个字节,编译器处理的难度会提升很多,容易造成乱码现象。利用空间换时间的思维,不论英文还是中文,都利用 unicode编码方式,全部在内存空间中占两个字节。
将内存空间占一个字节的变量类型 char ,改为内存空间占两个字节的变量类型 unsigned short int 。编写程序3:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
unsigned short int szHello[] = "Hello同学们";
printf("%s\r\n", szHello);
system("pause");
return 0;
}
因为字符串 "Hello同学们" 仍是 ascii编码方式,所以编译未通过,提示无法从 char [12] 转换为 unsigned short [],没有可以进行这种转换的环境。
在字符串前加 L ,如 L"我的字符串" 表示将 ascii编码字符串转换成 unicode编码的字符串。在字符串 "Hello同学们" 前加 L,编写程序4:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
unsigned short int szHello[] = L"Hello同学们";
printf("%s\r\n", szHello);
system("pause");
return 0;
}
编译通过。按 F10 进行单步调试,字符串中的每个字符和汉字都各占两个字节的内存空间。
printf 函数是按 ascii编码方式打印,默认字符串 \0 结尾,因为字符串 "Hello同学们" 是 unicode编码,所以在 H 字符后是 00 ,printf 看见 00 结束打印,只输出 H 。
查看 MSDN 可知,打印 unicode编码字符串,必须要用 wprintf 函数。因为 wprintf函数是 printf函数的宽字节版本,但两函数的行为相同。
将 printf 函数改为 wprintf 函数。编写程序5:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
unsigned short int szHello[] = L"Hello同学们";
wprintf(L"%s", szHello);
system("pause");
return 0;
}
编译执行,只输出了 Hello,而中文部分字符串"同学们"却没有输出。
只有利用 setlocale 函数,设置当前位置,才能显示中文部分的字符串。查看 MSDN,输出简体中文用 "chs" 。
根据 MSDN 获取到的修改方式,编写程序6:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <locale.h>
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "chs");
unsigned short int szHello[] = L"Hello同学们";
wprintf(L"%s\r\n", szHello);
system("pause");
return 0;
}
编译执行,输出 "Hello同学们" 成功。
04
可选择使用ascii编码或unicode编码
利用编译选项宏实现 ascii编码方式和unicode编码方式的随时切换,思路为如果定义宏 MYUNICODE ,代码全部为 unicode编码模式,否则代码全部为 ascii编码模式。编写程序7:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <locale.h>
#define MYUNICODE
#ifdef MYUNICODE
#define TCHAR unsigned short int
#define _tprintf wprintf
#define _tmain wmain
#define _tsetlocale _wsetlocale
#define _tsystem _wsystem
#define _T(x) L ## x
#else
#define TCHAR char
#define _tprintf printf
#define _tmain main
#define _tsetlocale setlocale
#define _tsystem system
#define _T(x) x
#endif
int main(int argc, char* argv[])
{
_tsetlocale(LC_ALL, _T("chs"));
TCHAR szHello[] = _T("Hello同学们");
_tprintf(_T("%s\r\n"), szHello);
_tsystem(_T("pause"));
return 0;
}
按 F10 进行单步调试,字符串以 unicode编码方式在内存中存储。
注释掉宏 MYUNICODE 。编写程序8:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <locale.h>
// #define MYUNICODE
#ifdef MYUNICODE
#define TCHAR unsigned short int
#define _tprintf wprintf
#define _tmain wmain
#define _tsetlocale _wsetlocale
#define _tsystem _wsystem
#define _T(x) L ## x
#else
#define TCHAR char
#define _tprintf printf
#define _tmain main
#define _tsetlocale setlocale
#define _tsystem system
#define _T(x) x
#endif
int main(int argc, char* argv[])
{
_tsetlocale(LC_ALL, _T("chs"));
TCHAR szHello[] = _T("Hello同学们");
_tprintf(_T("%s\r\n"), szHello);
_tsystem(_T("pause"));
return 0;
}
按 F10 进行单步调试,字符串以 ascii编码方式在内存中存储。