c++——Unicode编码和多字节编码的区别

1. VS项目属性不同字符集的区别

单字节字符集:顾名思义,单字节字符集就是用一个字节表示一个字符,简称SBCS。ASCII就是单字节字符集。在编码的过程中char类型就是单字节编码。

Unicode字符集:前面咱已经介绍什么是Unicode字符集了,不懂的请看前面的文章字符集与字符编码。默认编码是USC-2,即所有的字符都是固定的使用2个字节进行编码。因为比单字节字符宽,所有又叫宽字节编码。宽字节编码有很多,Unicode编码只是宽字节编码中的一种实现方式,其它的比如:USC-4。

多字节字符集:指使用多个字节表示一个字符,其实就是ANSI编码。有的字符使用一个字节,如ASCII字符,有的字符使用多个字节表示,如中文。英文名简称MBCS,由于Windows里使用的多字节字符绝大部分是两个字节,所以MBCS常被用**DBCS(双字节字符)**代替。

选择这两者的优缺点比较:

在这里插入图片描述

另外Unicode是国际通用的字符集,所以很容易在不同字符集之间进行转换,有利于软件的国际化。

2. wchar_t 、 _T 、TCHAR等含义

wchar_t意思是宽字节,w是Wide(宽)的缩写,所以只有在选择Unicode编码时才能使用。

wchar_t的定义为:typedef unsigned short wchar_t;
从这里我们可以看到,所谓的宽字节就是无符号短整型,即2个字节。
使用时前面加大写的“L”,比如:wchar_t str = L"Hello";*

选择宽字节字符集在编码的过程中字符串的类型是wchar_t,跟双字节字符集的类型char不一致,这样导致了两个问题:
1、像strlen()只能接受标准C字符的类型(char),所有使用char* 类型参数的函数都要重新
2、如何使编写的代码能够同时支持 多字节编码 和 宽字节(Unicode)编码的系统上运行?

对于第一个问题:
解决办法就是对函数进行重写,比如strlen的宽字节版本是wcslen,需要加入头文件Windows.h
需要注意的是:strlen是字符串的所占字节数,wcslen是字符串中字符个数,乘以2才是字节数。

对于第二个问题:
通过定义 宏 或者 起别名 的方式对 替代名称 做 不同定义 来实现的,比如tchar.h头文件中:

之所以能实现,主要通过编译器来实现,通过使用条件编译#ifdef _UNICODE(有下划线) 来对 替代名称 的不同定义。

在这里插入图片描述

这样子您就知道_T和TCHAR的啥意思了,它是为了方便程序员编码使用的。

说的这里了,您可能又有疑问了,哪里定义_UNICODE宏呢?

这里又回到最初了,我们在项目属性中选择 “使用多字节字符集” 或者 “使用Unicode字符集”时,VS在“C++ -> 预处理器”中增加了宏定义,分别是 _MBCS 和 _UNICODE,注意 _MBCS和_UNICODE是相互排斥的。

最后说一下一个细节,有Windows编码经验的人可能发现了,还有一个UNICODE宏,很多的定义跟_UNICODE是一样的,这是为什么呢?
UNICODE是Windows 提供的宏,Windows有一些系统API也要用到字符串,但是C库没有,比如:SetWindowText()和MessageBox()等,微软就对_UNICODE进行了重写和扩展,但是本质是一样,都是为了方便处理两种编码程序。
在这里插入图片描述

3. 字符转换

#include <locale>
#include <stdio.h>
#include <codecvt>

using namespace std;
//Unicode转ANSI
const std::string WstringToString(const std::wstring& src)
{
	std::locale sys_locale("");

	const wchar_t* data_from = src.c_str();
	const wchar_t* data_from_end = src.c_str() + src.size();
	const wchar_t* data_from_next = 0;

	int wchar_size = 4;
	char* data_to = new char[(src.size() + 1) * wchar_size];
	char* data_to_end = data_to + (src.size() + 1) * wchar_size;
	char* data_to_next = 0;

	memset(data_to, 0, (src.size() + 1) * wchar_size);

	typedef std::codecvt<wchar_t, char, mbstate_t> convert_facet;
	mbstate_t out_state = { 0 };
	auto result = std::use_facet<convert_facet>(sys_locale).out(
		out_state, data_from, data_from_end, data_from_next,
		data_to, data_to_end, data_to_next);
	if (result == convert_facet::ok)
	{
		std::string dst = data_to;
		delete[] data_to;
		return dst;
	}
	else
	{
		printf("convert error!\n");
		delete[] data_to;
		return std::string("");
	}
}

//ANSI转Unicode
const std::wstring StringToWstring(const std::string& src)
{
	std::locale sys_locale("");

	const char* data_from = src.c_str();
	const char* data_from_end = src.c_str() + src.size();
	const char* data_from_next = 0;

	wchar_t* data_to = new wchar_t[src.size() + 1];
	wchar_t* data_to_end = data_to + src.size() + 1;
	wchar_t* data_to_next = 0;

	wmemset(data_to, 0, src.size() + 1);

	typedef std::codecvt<wchar_t, char, mbstate_t> convert_facet;
	mbstate_t in_state = { 0 };
	auto result = std::use_facet<convert_facet>(sys_locale).in(
		in_state, data_from, data_from_end, data_from_next,
		data_to, data_to_end, data_to_next);
	if (result == convert_facet::ok)
	{
		std::wstring dst = data_to;
		delete[] data_to;
		return dst;
	}
	else
	{
		printf("convert error!\n");
		delete[] data_to;
		return std::wstring(L"");
	}
}

//Unicode转UTF-8
const std::string WstringToUTF8(const std::wstring& src)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
	return conv.to_bytes(src);
}

//UTF-8转Unicode
const std::wstring UTF8ToWstring(const std::string& src)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
	return conv.from_bytes(src);
}


//GBK转Unicode
wstring  GBKToWstring(const string &str)
{
	wstring_convert<codecvt<wchar_t, char, mbstate_t>> gbk_cvt(new codecvt<wchar_t, char, mbstate_t>("chs"));
	return gbk_cvt.from_bytes(str);
}

//Unicode转GBK
string  WstringToGBK(const wstring &str)
{
	wstring_convert<codecvt<wchar_t, char, mbstate_t>> gbk_cvt(new codecvt<wchar_t, char, mbstate_t>("chs"));
	return gbk_cvt.to_bytes(str);
}

//UTF8转GBK
string UTF8ToGBK(const string &str)
{
	wstring_convert<codecvt_utf8<wchar_t>> utf8_cvt; // utf8-》unicode转换器
	wstring_convert<codecvt<wchar_t, char, mbstate_t>> gbk_cvt(new codecvt<wchar_t, char, mbstate_t>("chs")); // unicode-》gbk转换器
	wstring t = utf8_cvt.from_bytes(str);
	return gbk_cvt.to_bytes(t);
}

//GBK转UTF8
string GBKToUTF8(const string &str)
{
	wstring_convert<codecvt_utf8<wchar_t>> utf8_cvt;
	wstring_convert<codecvt<wchar_t, char, mbstate_t>> gbk_cvt(new codecvt<wchar_t, char, mbstate_t>("chs")); // unicode-》gbk转换器
	wstring t = gbk_cvt.from_bytes(str);
	return utf8_cvt.to_bytes(t);
}

猜你喜欢

转载自blog.csdn.net/www_dong/article/details/114858915