编码和字符集那些事儿

基本概念

编码和字符集及其制定

字符集是人为规定的(相关标准委员会,如ISO/IEC)制定的,将”文字字符“与”数字“一一对应的静态表。

其中,每个”文字字符“对应的数字,也称为其编码

例如,ASCII码表就是一个字符集

字符集字符编码
ASCII‘A’65
ASCII‘0’48

字符 Character: 文字符号

字符集 Charset:字符的集合,规定一系列字符与数字(编码)的对应关系

字符集都是由某些组织指定和发布的,例如ISO/IEC就负责制定字符集。

每个字符集都有一个标准编号,例如ASCII字符集的编号为ISO/IEC 646(即,由ISO/IEC发布的第646号标准文档)

拉丁字符集 Latin

拉丁字符集:收录了欧洲各个国家的字符。例如,细佬字母 Aα Bβ
拉丁字符集的编号为 ISO 8859系列,例如:

  • ISO8859-1字符集,也就是Latin-1,是西欧常用字符,包括德法两国的字母。
  • ISO08859-2字符集,也称为Latin-2,收集了东欧字符。

中文字符集

  • GB2312 中文简体国际标码 (汉字数: 6763)
  • GBK 扩展中文GB编码(GB2312的超集, 兼容GB2312)
  • GB18030 用1-4个字节编码, 容量超大
  • BIG5 中文繁体编码
  • CJK 中日韩大字符集编码
  • Unicode 万国码(统一码), 用0-0x10FFFF来映射全球各国的语言文字

NOTE: GB(国标)

GB2312/GBK

双字节编码, 每个字节的高位为1,

汉字:2个字节

ASCII码:1个字节

不包含生僻字

对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致后来GBK以及GB18030汉字字符集的出现。

NOTE: GBK是GB2312的超集, 包含了GB2312, 较为常用

Unicode

Unicode是国际组织指定的可以容纳世界上所有文字和符号的字符编码方案。

Unicode可以用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符。那么用几个字节来表示一个字符呢?

第一种方案:UTF-32

每个字符用一个int来表示

特点:简单,但太浪费空间

第二种方案:UTF-16编码

特点:用1~2个short来表示一个字符

第三种方案:UTF-8编码

用1~4个字节来表示一个字符(比较节省空间)

在这里插入图片描述

乱码问题

上述的拉丁字符的总数远超256个,无法使用一个char型表示,得用两个字节表示。所以,即使不用中文,使用外文字母表示也是有问题的,例如:

char a = 'α'; // 这样无法正确表示

这和中文字符问题的原因是相同的:无法使用一个字节来表示一个字符。

在这里插入图片描述

字符编码的转换

什么时候需要编码转换?

例如:你的字符串按照GBK编码,但是对方要求按UTF-16编码。

char str[] = "你好";

4个字节,发送给对方,但是对方只接受UTF-16编码。。。

VC下的转换方法

不同的平台都提供了函数来做编码转换,这里介绍在VC下的编码转换方法,其他平台下的后续有时间再补上。

VC中,用wchar_t代表宽字符, 相当于short型。一个wchar_t的数据来存放unicode字符。

NOTE: 在源代码中写出“你好”两个字符的编码是啥? 这取决于你源代码本身的编码。

例如,在Linux上,一般默认的字符集是UTF-8的,“你好”的编码就是UTF-8的,所以他是6个字节。

而在Windows中文版本上,默认按GBK编码,所以它是4个字节。

	
#include <stdio.h>
#include <stdlib.h>

// 头文件
#include <winsock2.h>
#include <windows.h>

// GBK -> UTF-16
int test1()
{
	//char text_gbk[] = { 0xC9, 0xDB, 0xB7, 0xA2, 0};
	char text_gbk[] = "你好"; // 字符串字面常量,取决于cpp文件本身的字符集
	wchar_t text_utf16[256] = { 0 };
	int n = MultiByteToWideChar(CP_ACP, 0,
		text_gbk, strlen(text_gbk),
		text_utf16, 256);

	printf("结果: %d 个宽字符 \n", n);

	n = sizeof(text_gbk);

	return 0;
}

// GBK -> UTF-16 -> UTF-8
int test2()
{
	char text_gbk[] = "你好"; // 字符串字面常量,取决于cpp文件本身的字符集

	//
	wchar_t text_utf16[256] = { 0 };
	int n1 = MultiByteToWideChar(CP_ACP, 0, text_gbk, strlen(text_gbk), text_utf16, 256);
	printf("结果: %d 个宽字符 \n", n1);

	// 
	char text_utf8[256];
	int n2 = WideCharToMultiByte(CP_UTF8, 0, text_utf16, n1, text_utf8, 256, NULL, 0);
	printf("结果: %d 个字节 \n", n2);

	return 0;
}

int main()
{
	//test1();
	test2();

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值