C++与字符集、字符编码

 

目录linux

 

问题c++

字符集git

字符编码github

字符集与字符编码的关系shell

多种字符编码存在的意义数据库

字符编码的发展历史数组

活动代码页编码

c++的多字节字符与宽字节字符spa

c++的多字节字符串与宽字节字符串操作系统

C++程序输出字符串的编码

字符串常量

参考文章


问题

字符集和编码每每是IT菜鸟甚至是各类大神的头痛问题。当遇到纷繁复杂的字符集,各类火星文和乱码时,问题的定位每每变得很是困难。本文就将会从原理方面对字符集和编码作个简单的科普介绍,同时也会介绍C++中设置字符串编码以及编码转换的一些方法。

字符集

简单的说,字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值表明了哪一个文字(解码)的转换关系。常见的字符集如ASCII、GB23十二、GBK等。

下面就是这个字在各类编码下的十六进制和二进制编码结果

字符编码

字符集只是一个规则集合的名字,对应到真实生活中,字符集就是对某种语言的称呼。例如:英语,汉语,日语。

对于一个字符集来讲要正确编码转码一个字符须要三个关键元素:字库表、编码字符集、字符编码。

字库表是一个至关于全部可读或者可显示字符的数据库,字库表决定了整个字符集可以展示表示的全部字符的范围。

编码字符集,即用一个编码值来表示一个字符在字库中的位置。

字符编码定义编码字符集和实际存储数值之间的转换关系。通常来讲,都会直接将字符的编码值直接进行存储。例如在ASCII中A在表中排第65位,而编码后A的数值是0100 0001也即十进制的65的二进制转换结果。

字符集与字符编码的关系

通常一个字符集等同于一个编码方式,ANSI体系的字符集如ASCII、ISO 8859-一、GB23十二、GBK等等都是如此。通常咱们说一种编码都是针对某一特定的字符集。
一个字符集上也能够有多种编码方式,例如UCS字符集(也是Unicode使用的字符集)上有UTF-八、UTF-1六、UTF-32等编码方式。

多种字符编码存在的意义

既然字库表中的每个字符都有一个本身的序号,直接把序号做为存储内容就行了。为何还要画蛇添足经过字符编码把序号转换成另一种存储格式呢?

统一字库表的目的是为了可以涵盖世界上全部的字符,但实际使用过程当中会发现真正用的上的字符相对整个字库表来讲比例很是低。例如中文地区的程序几乎不会须要日语字符,而一些英语国家甚至简单的ASCII字库表就能知足基本需求。而若是把每一个字符都用字库表中的序号来存储的话,每一个字符就须要3个字节(这里以Unicode字库为例),这样对于本来用仅占一个字符的ASCII编码的英语地区国家显然是一个额外成本(存储体积是原来的三倍)。因而就出现了UTF-8这样的变长编码。在UTF-8编码中本来只须要一个字节的ASCII字符,仍然只占一个字节。而像中文及日语这样的复杂字符就须要2个到3个字节来存储。

字符编码的发展历史

第一个阶段:ASCII字符集和ASCII编码
计算机刚开始只支持英语(即拉丁字符),其它语言不可以在计算机上存储和显示。ASCII用一个字节(Byte)的7位(bit)表示一个字符,第一位置0。后来为了表示更多的欧洲经常使用字符又对ASCII进行了扩展,又有了EASCII,EASCII用8位表示一个字符,使它能多表示128个字符,支持了部分西欧字符。

第二个阶段:ANSI编码(本地化)
为使计算机支持更多语言,一般使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。好比:汉字 ‘中’ 在中文操做系统中,使用 [0xD6,0xD0] 这两个字节存储。
不一样的国家和地区制定了不一样的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来表明一个字符的各类汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码表明 GB2312 编码,在日文操做系统下,ANSI 编码表明 JIS 编码。
不一样 ANSI 编码之间互不兼容,当信息在国际间交流时,没法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。

第三个阶段:UNICODE(国际化)
为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各类语言中的每个字符设定了统一而且惟一的数字编号,以知足跨语言、跨平台进行文本转换、处理的要求。UNICODE 常见的有三种编码方式:UTF-8(1-4个字节表示)、UTF-16((2个字节表示))、UTF-32(4个字节表示)。

活动代码页

代码页是字符集编码的别名,也有人称"内码表"。

早期,代码页是IBM称呼电脑BIOS自己支持的字符集编码的名称。当时通用的操做系统都是命令行界面系统,这些操做系统直接使用BIOS供应的VGA功能来显示字符,操做系统的编码支持也就依靠BIOS的编码。如今这BIOS代码页被称为OEM代码页。图形操做系统解决了此问题,图形操做系统使用本身字符呈现引擎能够支持不少不一样的字符集编码。

早期IBM和微软内部使用特别数字来标记这些编码,其实大多的这些编码已经有本身的名称了。虽然图形操做系统能够支持不少编码,不少微软程序还使用这些数字来点名某编码。
下表列出了部分代码页及其国家(地区)或者语言:
代码页 国家(地区)或语言
437 美国
932 日文(Shift-JIS)
936 中国 - 简体中文(GB2312)
950 繁体中文(Big5)
1200 Unicode
1201 Unicode (Big-Endian)
50220 日文(JIS)
50225 韩文(ISO)
50932 日文(自动选择)
50949 韩文(自动选择)
52936 简体中文(HZ)
65000 Unicode (UTF-7)
65001 Unicode (UTF-8)

c++的多字节字符与宽字节字符

C++基本数据类型中表示字符的有两种:char、wchar_t。
char叫多字节字符,一个char占一个字节,之因此叫多字节字符是由于它表示一个字时多是一个字节也多是多个字节。一个英文字符(如’s’)用一个char(一个字节)表示,一个中文汉字(如’中’)用2个char(二个字节)表示,看下面的例子。

void TestChar()
{
	char ch1 = 's';				// 正确
	cout << "ch1:" << ch1 << endl;
	char ch2 = '中';				// 错误,一个char不能完整存放一个汉字信息
	cout << "ch2:" << ch2 << endl;

	char str[3] = "中";			//前二个字节存放汉字'中',最后一个字节存放字符串结束符\0
	cout << "str:" << str << endl;
}

c++的多字节字符串与宽字节字符串

字符数组能够表示一个字符串,但它是一个定长的字符串,咱们在使用以前必须知道这个数组的长度。为方便字符串的操做,STL为咱们定义好了字符串的类string和wstring。你们对string确定不陌生,但wstring可能就用的少了。

string是普通的多字节版本,是基于char的,对char数组进行的一种封装。

wstring是Unicode版本,是基于wchar_t的,对wchar_t数组进行的一种封装。

###string 与 wstring的相关转换:
如下的两个方法是跨平台的,可在Windows下使用,也可在Linux下使用。

C++程序输出字符串的编码

C++程序输出的字符串编码规则以下:

  1. 若程序中指定了字符串的编码,则输出字符串的编码与指定编码相同;
  2. 若程序中没有指定字符串的编码,则输出字符串的编码与程序在编译时Windows代码页编码相同(Linux状况还没有实验);
  3. 程序输出字符串的编码与程序源文件编码无关;

对规则1的证明可使用以下代码:

#include <fstream>

int main() 
{
	using namespace std;

	ofstream OutFile("OutInUTF8.txt");
	OutFile << "你" << endl;
	OutFile.close();

	return 0;
}

以上代码在活动代码页为GBK的Window中生成的txt文件的编码是UTF8。

对规则2的证明可使用以下代码:

#include <fstream>

int main() 
{
	using namespace std;

	ofstream OutFile("Output.txt");
	OutFile << "你" << endl;
	OutFile.close();

	return 0;
}

上面的程序若是编译时Window的代码页是936(GBK),结果生成的txt文件编码也是GBK。即便将该程序在Window的代码页为65001(UTF8)的Windows系统中运行,生成的txt文件编码依然是GBK。

对规则3的证明

仍然使用上面的程序。可是其源文件编码设成UTF8,而后在代码页是936(GBK)的Window系统上编译,结果生成的txt文件编码是GBK。

字符串常量

C++98标准中一些表示字符串常量的标识有:

  • "您好": string字符串常量(字节数组),使用当前系统代码页进行编码

C++11标准中增长了一些表示字符串常量的标识,以下有:

  • L"您好!": wstring字符串常量,使用文件保存编码方式字符集
  • R"(您好 \n)": 原始字符串常量(字节数组),保留全部的字符
  • u8"您好!": string字符串常量(字节数组),使用UTF8进行编码保存

可用如下程序进行验证

#include <string>


int main() 
{
	using namespace std;

	string str;
	wstring wstr;
	
	str = "你好";
	wstr = "你好";	//编译报错——“初始化”: 没法从“const char [3]”转换为“std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>”
					
	str = L"你好";	//编译报错——没法从“const wchar_t [2]”转换为“std::basic_string<char,std::char_traits<char>,std::allocator<char>>”
	wstr = L"你好";
	
	str = R"(你好)";
	wstr = R"(你好)";//编译报错——二进制“=”: 没有找到接受“const char [5]”类型的右操做数的运算符(或没有可接受的转换)

	return 0;
}

参考文章

带你玩转Visual Studio——带你理解多字节编码与Unicode码

十分钟搞清字符集和字符编码

活动代码页简介

Windows:如何设置Windows的默认代码页

C++中wchar_t与wstring理解及中文编码的处理