windows下c/c++编程GBK、UTF8、UNICODE字符集互转详解

简介

windows下进行C/C++编程时,需要处理各种各样的网络数据、文本数据,由于数据编码可能不一样,这时就需要对数据进行转码,否则程序将无法正常工作。
常用的数据编码有GBK(GB2312)、UTF-8、UNICODE,具体的字符集相关知识我会单独写一篇文档进行描述,下面列出这三种字符集相互之间互转的封装函数。

头文件

这里使用了windows的两个库函数MultiByteToWideChar、WideCharToMultiByte
涉及到的头文件:
函数所在头文件:Windows.h
#include <Windows.h>

wchar_t类型所需头文件:wchar.h
#include <wchar.h>

函数1:多字节转unicode

/*********************************************************************
函数名      : multiByteToUnicode
功能        : 将多字节字符串转换为Unicode字符串(例如:gbk字符串转为unicode字符串;utf-8字符串转为unicode字符串)
参数        : 
              multiByteStr:指向待转换的字符串的缓冲区
              multiByteStrLen:指定由参数multiByteStr指向的字符串中字节的个数
			  multiByteCharsetFlag:指定执行转换的多字节字符所使用的字符集,可选值有CP_ACP(gbk/gb2312)、CP_UTF8(utf-8)
			  unicodeStr:指向接收被转换字符串的缓冲区
			  unicodeStrLen:指定由参数unicodeStr指向的缓冲区的字节数
返回值      : 成功时,返回解析好的字节个数,错误时,返回相应错误码(-1:待转换的字符串为空;-2:待转换的字符串的长度小于等于0;-3:字符集设置不合理,必须               是CP_ACP和CP_UTF8之一;-4:接收转换字符串缓存区为空;-5:接收转换字符串缓存区长度小于等于0;-6:接收被转换字符串的缓冲区小于实际需要的字节                数)
日期        : 2018-09-26
作者        : xxx
*********************************************************************/
int multibyteToUnicode(const char *multiByteStr,int multiByteStrLen,UINT multiByteCharsetFlag,char *unicodeStr,int unicodeStrLen)
{
	if (multiByteStr==NULL)//原始字符串为空
	{
		return -1;
	}

	if (multiByteStrLen<=0)//原始字符串长度小于等于0
	{
		return -2;
	}

	if (multiByteCharsetFlag!=CP_ACP && multiByteCharsetFlag!=CP_UTF8)//原始字符串字符集标识既不是GBK/GB2312又不是UTF-8
	{
		return -3;
	}

	if (unicodeStr==NULL)//用于存放unicode串的缓存区为空
	{
		return -4;
	}

	if (unicodeStrLen<=0)//用于存放unicode串的缓存区的长度小于等于0
	{
		return -5;
	}

	int requiredUnicode=MultiByteToWideChar(multiByteCharsetFlag,0,multiByteStr,multiByteStrLen,NULL,0);//此种情况用来获取转换所需的wchar_t的个数

	if(sizeof(WCHAR)*requiredUnicode>unicodeStrLen)//接收被转换字符串的缓冲区小于实际需要的字节数
	{
		return -6;
	}

	WCHAR *tmp=new WCHAR[requiredUnicode];//动态分配unicode临时缓存区

	wmemset(tmp,0,requiredUnicode);//将临时缓存区数据清零

	//执行真实转换,并将转换后的unicode串写到tmp缓存区
	int parsedUnicode=MultiByteToWideChar(multiByteCharsetFlag,0,multiByteStr,multiByteStrLen,tmp,requiredUnicode);

	if (parsedUnicode!=requiredUnicode)//判断真实解析的unicode字符数和分配的字符数是否一致
	{
		delete []tmp;
		tmp=NULL;
		return -7;
	}

	memset(unicodeStr,0,unicodeStrLen);//将目标unicode缓存区清零
	memcpy(unicodeStr,tmp,sizeof(WCHAR)*requiredUnicode);//将数据由临时缓存区拷贝到目标unicode缓存区

	delete [] tmp;//释放空间
	tmp=NULL;

	return sizeof(WCHAR)*requiredUnicode;//返回解析好的总字节数
}

函数2:unicode转多字节

/*********************************************************************
函数名      : unicodeToMultibyte
功能        : 将Unicode字符串转换为多字节字符串(例如:将unicode字符串转换为gb2312/utf-8编码的字符串)
参数        : 
              unicodeStr:指向待转换的unicode字符串的缓冲区,该字符串必须是小端字节序
              unicodeStrLen:指定由参数unicodeStr指向的字符串中字节的个数
			  multiByteStr:指向接收被转换字符串的缓冲区
			  multiByteStrLen:指定由参数multiByteStr指向的缓冲区的字节数
			  multiByteCharsetFlag:指定目标字符串所使用的字符集,可选值有CP_ACP(gbk/gb2312)、CP_UTF8(utf-8)
返回值      : 成功时,返回解析好的字节个数,错误时,返回相应错误码(-1:待转换的字符串为空;-2:待转换的字符串的长度小于等于0;-3:接收转换字符串缓存区为                 空;-4:接收转换字符串缓存区长度小于等于0;-5:字符集设置不合理,必须是CP_ACP和CP_UTF8之一;-6:接收被转换字符串的缓冲区小于实际需要的字节数)
日期        : 2018-09-27
作者        : xxx
*********************************************************************/
int unicodeToMultibyte(const char *unicodeStr,int unicodeStrLen,char *multiByteStr,int multiByteStrLen,UINT multiByteCharsetFlag)
{
	if (unicodeStr==NULL)//原始unicode字符串为空
	{
		return -1;
	}

	if (unicodeStrLen<=0)//原始unicode字符串的长度小于等于0
	{
		return -2;
	}

	if (multiByteStr==NULL)//用于存放多字节字符串的缓存区为空
	{
		return -3;
	}

	if (multiByteStrLen<=0)//用于存放多字节字符串的缓存区的长度小于等于0
	{
		return -4;
	}
	
	if (multiByteCharsetFlag!=CP_ACP && multiByteCharsetFlag!=CP_UTF8)//目标字符串所使用的字符集既不是CP_ACP(gbk/gb2312)又不是CP_UTF8(utf-8)
	{
		return -5;
	}

	WCHAR *tmp=new WCHAR[unicodeStrLen/2];//动态分配用于存放原始Unicode字符串的临时缓存区

	wmemset(tmp,0,unicodeStrLen/2);//将临时缓存区清零
	
	memcpy(tmp,unicodeStr,unicodeStrLen);//将原始Unicode字符串拷贝到临时缓存区

	int requiredByte=WideCharToMultiByte(multiByteCharsetFlag,0,tmp,unicodeStrLen/2,NULL,0,NULL,NULL);//获取用于存放目标字符串的字节数

	if (requiredByte>multiByteStrLen)//接收被转换字符串的缓冲区小于实际需要的字节数
	{
		delete []tmp;
		tmp=NULL;
		return -6;
	}


	memset(multiByteStr,0,multiByteStrLen);//将目标缓存区清零
	//执行真正转换,将转换后的多字节字符串存放到目标缓存区中,并返回实际解析的字节数
	int parsedByte=WideCharToMultiByte(multiByteCharsetFlag,0,tmp,unicodeStrLen/2,multiByteStr,multiByteStrLen,NULL,NULL);
	if (parsedByte!=requiredByte)//实际解析的字节数不正确
	{
		delete []tmp;
		tmp=NULL;	
		return -7;
	}

	delete []tmp;//释放临时缓存区
	tmp=NULL;
	
	return parsedByte;//返回解析好的总字节数
}

函数3:gbk转utf8

/*********************************************************************
函数名      : gbkToUtf8
功能        : 将gbk编码的字符串转换为utf8编码的字符串
参数        : 
              gbkstr:指向待转换的gbk字符串的缓冲区
              gbkstrlen:指定由参数gbkstr指向的字符串中字节的个数
			  utf8str:指向接收被转换字符串的缓冲区
			  utf8strlen:指定由参数utf8str指向的缓冲区的字节数
返回值      : 成功时,返回解析好的字节个数,错误时,返回相应错误码(-1:字符串为空或长度小于等于0;-2:gbk转unicode失败;-3:unicode转utf-8失败)
日期        : 2018-09-27
作者        : xxx
*********************************************************************/
int gbkToUtf8(const char * gbkstr,int gbkstrlen,char * utf8str,int utf8strlen)
{
	if (gbkstr==NULL || gbkstrlen<=0 || utf8str==NULL || utf8strlen<=0)//字符串为空或长度小于等于0
	{
		return -1;
	}

	char *unicodestr=new char[2*gbkstrlen];//分配缓存区,长度为gbk字符串长度的2倍

	int unicodebytes=multibyteToUnicode(gbkstr,gbkstrlen,CP_ACP,unicodestr,2*gbkstrlen);//gbk转unicode

	if (unicodebytes<0)//gbk转unicode失败
	{
		delete [] unicodestr;
		unicodestr=NULL;
		return -2;
	}

	int utf8bytes=unicodeToMultibyte(unicodestr,unicodebytes,utf8str,utf8strlen,CP_UTF8);//unicode转utf-8

	if (utf8bytes<0)//unicode转utf-8失败
	{
		delete [] unicodestr;
		unicodestr=NULL;
		return -3;
	}

	delete [] unicodestr;//释放内存
	unicodestr=NULL;

	return utf8bytes;//返回解析好的总utf8字节数
}

函数4:utf8转gbk

/*********************************************************************
函数名      : utf8ToGbk
功能        : 将utf8编码的字符串转换为gbk编码的字符串
参数        : 
              utf8str:指向待转换的utf8字符串的缓冲区
              utf8strlen:指定由参数utf8str指向的字符串中字节的个数
			  gbkstr:指向接收被转换字符串的缓冲区
			  gbkstrlen:指定由参数gbkstr指向的缓冲区的字节数
返回值      : 成功时,返回解析好的字节个数,错误时,返回相应错误码(-1:字符串为空或长度小于等于0;-2:utf8转unicode失败;-3:unicode转gbk失败)
日期        : 2018-09-27
作者        : xxx
*********************************************************************/
int utf8ToGbk(const char * utf8str,int utf8strlen,char * gbkstr,int gbkstrlen)
{
	if (utf8str==NULL || utf8strlen<=0 || gbkstr==NULL || gbkstrlen<=0)//字符串为空或长度小于等于0
	{
		return -1;
	}

	char *unicodestr=new char[2*utf8strlen];//分配缓存区,长度为utf8字符串长度的2倍

	int unicodebytes=multibyteToUnicode(utf8str,utf8strlen,CP_UTF8,unicodestr,2*utf8strlen);//utf8转unicode

	if (unicodebytes<0)//utf8转unicode失败
	{
		delete [] unicodestr;
		unicodestr=NULL;
		return -2;
	}

	int gbkbytes=unicodeToMultibyte(unicodestr,unicodebytes,gbkstr,gbkstrlen,CP_ACP);//unicode转GBK

	if (gbkbytes<0)//unicode转gbk失败
	{
		delete [] unicodestr;
		unicodestr=NULL;
		return -3;
	}

	delete [] unicodestr;
	unicodestr=NULL;

	return gbkbytes;//返回解析好的gbk字节数
}

参考文献

https://www.cnblogs.com/ranjiewen/p/5770639.html

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Linux下,可以使用iconv库进行Unicode编码转换。下面是一个示例代码,将Unicode字符串转换成字节数组、将字节数组转换Unicode字符串: ```c++ #include <iconv.h> #include <string.h> #include <stdio.h> int main() { // 将Unicode字符串转换成字节数组 const char *unicode_str = u8"\u4F60\u597D"; size_t unicode_len = strlen(unicode_str); size_t buf_len = unicode_len * 4; // 一个Unicode字符最多占4个字节 char *buf = new char[buf_len]; memset(buf, 0, buf_len); iconv_t cd = iconv_open("UTF-8", "UCS-2LE"); char *in_buf = (char*)unicode_str; char *out_buf = buf; size_t in_len = unicode_len; size_t out_len = buf_len; int ret = iconv(cd, &in_buf, &in_len, &out_buf, &out_len); if (ret == -1) { perror("iconv"); return -1; } printf("字节数组: "); for (size_t i = 0; i < buf_len - out_len; ++i) { printf("%02X ", (unsigned char)buf[i]); } printf("\n"); // 将字节数组转换Unicode字符串 char *byte_str = buf; size_t byte_len = buf_len - out_len; size_t unicode_buf_len = byte_len / 2 + 1; // 一个Unicode字符占2个字节 char *unicode_buf = new char[unicode_buf_len]; memset(unicode_buf, 0, unicode_buf_len); cd = iconv_open("UCS-2LE", "UTF-8"); in_buf = byte_str; out_buf = unicode_buf; in_len = byte_len; out_len = unicode_buf_len; ret = iconv(cd, &in_buf, &in_len, &out_buf, &out_len); if (ret == -1) { perror("iconv"); return -1; } printf("Unicode字符串: %s\n", unicode_buf); delete[] buf; delete[] unicode_buf; return 0; } ``` 需要注意的是,iconv库只能处理单个Unicode字符,如果要处理Unicode字符串,则需要将其拆分成单个Unicode字符进行转换。上面的示例代码中,使用了UCS-2LE编码,可以根据需要修改为其他编码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

历史五千年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值