GBK,Unicode,UTF-8相互转化 C语言

对于开发物联网或者跟网络相关的人员来说应对不同的编码转换尤其麻烦,如果所用的库有当然最好,对于单片机开发或者一些其他开发来说,库就相对少点或者不好找,所以就总结了一份来方便使用。

最近搞了一段时间联网的产品,因为需要连接服务器,而自己的系统用的编码是GBK的,所以数据编码方式会有所差异,需要我们自行转化编码来让系统可以理解传的数据的含义(包括自己)。

在网上找了很久相关的资料,GBk与Unicode,utf8之间是没有明确的转换公式,主流还是使用查表法来索引对应的编码。Unicode与utf8之间就存在对应的转换(工程使用vs搭建的,代码用C语言)

/*****************************************************************************
* 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码.
*
* 参数:
*    unic     字符的Unicode编码值
*    pOutput  指向输出的用于存储UTF8编码值的缓冲区的指针
*    outsize  pOutput缓冲的大小
*
* 返回值:
*    返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 .
*
* 注意:
*     1. UTF8没有字节序问题, 但是Unicode有字节序要求;
*        字节序分为大端(Big Endian)和小端(Little Endian)两种;
*        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
*     2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小!
****************************************************************************/
int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput,
	int outSize)
{
	//assert(pOutput != NULL);  
	//assert(outSize >= 6);  
	if (pOutput == NULL || outSize<6) return 0;

	if (unic <= 0x0000007F)
	{
		// * U-00000000 - U-0000007F:  0xxxxxxx  
		*pOutput = (unic & 0x7F);
		return 1;
	}
	else if (unic >= 0x00000080 && unic <= 0x000007FF)
	{
		// * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
		*(pOutput + 1) = (unic & 0x3F) | 0x80;
		*pOutput = ((unic >> 6) & 0x1F) | 0xC0;
		return 2;
	}
	else if (unic >= 0x00000800 && unic <= 0x0000FFFF)
	{
		// * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 2) = (unic & 0x3F) | 0x80;
		*(pOutput + 1) = ((unic >> 6) & 0x3F) | 0x80;
		*pOutput = ((unic >> 12) & 0x0F) | 0xE0;
		return 3;
	}
	else if (unic >= 0x00010000 && unic <= 0x001FFFFF)
	{
		// * U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 3) = (unic & 0x3F) | 0x80;
		*(pOutput + 2) = ((unic >> 6) & 0x3F) | 0x80;
		*(pOutput + 1) = ((unic >> 12) & 0x3F) | 0x80;
		*pOutput = ((unic >> 18) & 0x07) | 0xF0;
		return 4;
	}
	else if (unic >= 0x00200000 && unic <= 0x03FFFFFF)
	{
		// * U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 4) = (unic & 0x3F) | 0x80;
		*(pOutput + 3) = ((unic >> 6) & 0x3F) | 0x80;
		*(pOutput + 2) = ((unic >> 12) & 0x3F) | 0x80;
		*(pOutput + 1) = ((unic >> 18) & 0x3F) | 0x80;
		*pOutput = ((unic >> 24) & 0x03) | 0xF8;
		return 5;
	}
	else if (unic >= 0x04000000 && unic <= 0x7FFFFFFF)
	{
		// * U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
		*(pOutput + 5) = (unic & 0x3F) | 0x80;
		*(pOutput + 4) = ((unic >> 6) & 0x3F) | 0x80;
		*(pOutput + 3) = ((unic >> 12) & 0x3F) | 0x80;
		*(pOutput + 2) = ((unic >> 18) & 0x3F) | 0x80;
		*(pOutput + 1) = ((unic >> 24) & 0x3F) | 0x80;
		*pOutput = ((unic >> 30) & 0x01) | 0xFC;
		return 6;
	}

	return 0;
}
/*****************************************************************************
* 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码.
*
* 参数:
*    pInput      指向输入缓冲区, 以UTF-8编码
*    Unic        指向输出缓冲区, 其保存的数据即是Unicode编码值,
*                类型为unsigned long .
*
* 返回值:
*    成功则返回该字符的UTF8编码所占用的字节数; 失败则返回0.
*
* 注意:
*     1. UTF8没有字节序问题, 但是Unicode有字节序要求;
*        字节序分为大端(Big Endian)和小端(Little Endian)两种;
*        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
****************************************************************************/
int enc_utf8_to_unicode_one(const unsigned char* pInput, unsigned long *Unic)
{
	extern int enc_get_utf8_size(const unsigned char pInput);
	//assert(pInput != NULL && Unic != NULL);  
	if (pInput == NULL || Unic == NULL) return 0;

	// b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...  
	char b1, b2, b3, b4, b5, b6;

	*Unic = 0x0; // 把 *Unic 初始化为全零  
	int utfbytes = enc_get_utf8_size(*pInput);
	unsigned char *pOutput = (unsigned char *)Unic;

	switch (utfbytes)
	{

关于GBK与Unicode,utf8区别

GBK对于单片机开发的应该不陌生,目前有几个版本,但是都是往下兼容,用的时候其实也没啥顾忌的。常用的是GB2312与GB18030,前者虽然收录的汉字不全(其实最新也未必全,毕竟每时每刻都有可能有新的汉字被收录),但是起码常用的都有,占用的空间也相对小很多,适合rom小的设备使用。后者就相对全很多,不用担心输入生僻字却显示了寂寞。在window上如果设置地区是中国或者语言是大陆的,编码其实都是GBK的编码。对于中文来说一个汉字占用2个字节。

Unicode相对国际化一点可以表示世界内所有文字(前提是收录进去了),最大4个字节代表一个字。我们常用的短信其实就是用Unicode编码的。对于中文来说一个汉字占用2个字节(大概)

utf-8是Unicode变种而来,可能因为好用吧,基本服务器跟浏览器都是使用utf-8替代以前的Unicode,可能还有一些没改,但是主流都是使用这个了,相信不久就全部都改成utf-8。所以基本我们使用的话都是将utf-8转成我们系统上所使用的编码。对于中文来说一个汉字占用3个字节

eg:对于英文及普通字符,所有编码都是一样的,都是占用一个字节 ,详细可以查看ASCII表 

分享一个网站 http://www.mytju.com/classCode/tools/encode_gb2312.asp

这个可以查看文字所对应的数据是怎样的

比如中文  ‘一’

对应GBK为        0xD2BB

对应Unicode为        0x4E00

对应utf-8为        0xE4B880

关于GBK与Unicode,utf8互转,这里是使用查表法,首先都是GBK与Unicode之间相互转化,再进而转成utf8

WCHAR ff_convert (	/* Converted code, 0 means conversion error */
	WCHAR	chr,	/* Character code to be converted */
	UINT	dir		/* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
	const WCHAR *p;
	WCHAR c;
	int i, n, li, hi;


	if (chr < 0x80) {	/* ASCII */
		c = chr;
	} else {
		if (dir) {		/* OEM code to unicode */
			p = oem2uni;
			hi = sizeof oem2uni / 4 - 1;
		} else {		/* Unicode to OEM code */
			p = uni2oem;
			hi = sizeof uni2oem / 4 - 1;
		}
		li = 0;
		for (n = 16; n; n--) {
			i = li + (hi - li) / 2;
			if (chr == p[i * 2]) break;
			if (chr > p[i * 2])
				li = i;
			else
				hi = i;
		}
		c = n ? p[i * 2 + 1] : 0;
	}

	return c;
}

其中 oem2uni与uni2oem就是对应的表

下面提供了自己整理的函数跟测试例子,大家可以按需求下载,都是一样的文件。转换有的是单个转换有的是整个数组一次性转的,使用的时候要看清楚。

免费共享通道

链接:https://pan.baidu.com/s/1dbX-_som28s61I4P_wzRBg 
提取码:i0g1

付费支持下载

https://download.csdn.net/download/qq_41851997/20979303

来源、参考、鸣谢(部分,还有忘了找不到,不代表最终来源)

https://www.amobbs.com/thread-4805076-1-1.html
https://www.cnblogs.com/mickole/articles/3663924.html

cc936.c -- 正点原子

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: GBKUTF-8是两种不同的字符编码方式,GBK是中国的编码方式,而UTF-8是一种国际通用的编码方式。在实际开发过程中,由于不同平台和程序使用的编码方式不同,会出现需要进行GBKUTF-8之间的互转的情况。 在C语言中,实现GBKUTF-8的互转,可以使用iconv函数。iconv函数是一个系统函数,用于进行字符编码的转换。在进行转换的时候,需要提供源编码和目标编码,同时也需要传入需要进行转换的字符串和字符串的长度。 具体的实现过程如下: 1. 获取需要转换的字符串和字符串的长度。 2. 定义iconv_t类型的变量,用于存储转换方式。 3. 调用iconv_open函数,打开转换方式,获取iconv_t类型的变量。 4. 定义一个用于存储转换后字符串的char数组和数组长度。 5. 调用iconv函数,将源编码的字符串转换为目标编码的字符串。 6. 关闭iconv_t类型的变量。 7. 返回转换后的字符串。 下面是一个简单的示例代码: ``` #include <iconv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { char gbk_str[100] = "这是一个GBK编码的字符串"; char utf8_str[100] = {0}; char *inbuf = gbk_str; char *outbuf = utf8_str; size_t inlen = strlen(gbk_str); size_t outlen = strlen(utf8_str); iconv_t ic = iconv_open("utf-8","gbk"); if(ic == (iconv_t)-1) { perror("iconv_open"); exit(1); } int ret = iconv(ic, &inbuf, &inlen, &outbuf, &outlen); if(ret == -1) { perror("iconv"); exit(1); } printf("gbk_str: %s\nutf8_str: %s\n", gbk_str, utf8_str); iconv_close(ic); return 0; } ``` 这段代码将一个GBK编码的字符串转换为UTF-8编码的字符串,最终输出转换后的字符串。可以看到,使用iconv函数可以非常方便地进行编码的转换。 ### 回答2: GBKUTF-8是两种常见的字符编码方式,它们的字节长度和编码规则不同。如何进行互转呢?我们可以通过C语言实现。 首先,需要了解GBKUTF-8编码的规则。GBK是双字节编码,每个字符占用2个字节,而UTF-8是变长编码,每个字符的字节长度不同,最长可达4个字节。 其次,需要用C语言写出转换函数。以将GBK转为UTF-8为例,可按如下步骤进行: 1. 定义两个指针,一个指向源字符串GBK,一个指向目标字符串UTF-8。 2. 使用循环遍历GBK字符串中的每个字符。 3. 如果字符的高位为0,表示该字符为ASCII字符,将该字符直接复制到UTF-8字符串中。 4. 如果字符的高位为1,表示该字符为汉字或其他非ASCII字符,需要将该字符转为UTF-8编码。 5. 将该字符的二进制形式转为Unicode编码,再根据以下规则将Unicode编码转为UTF-8编码: - 对于1字节的UTF-8编码,Unicode编码的范围为U+0000~U+007F; - 对于2字节的UTF-8编码,Unicode编码的范围为U+0080~U+07FF; - 对于3字节的UTF-8编码,Unicode编码的范围为U+0800~U+FFFF; - 对于4字节的UTF-8编码,Unicode编码的范围为U+10000~U+10FFFF。 6. 将得到的UTF-8编码复制到目标字符串UTF-8中,并移动目标字符串指针。 7. 循环结束后,在目标字符串UTF-8的末尾添加一个\0字符,表示字符串的结束。 最后,我们需要注意转换时可能会出现一些错误,如GBK字符串中包含非法字符等。因此,在实现时需要对这些情况进行判断和处理。 总的来说,通过以上步骤,我们就能够将GBK字符串转为UTF-8编码的字符串了。同样的,我们也可以实现将UTF-8字符串转为GBK编码的函数。 ### 回答3: GBKUTF-8是两种编码格式,GBK适用于汉字编码,UTF-8适用于多语言编码。想要在C语言中进行互转需要先了解一些基本操作。 UTF-8编码格式使用变长字节,一个字符可以由1-4个字节组成,其中第一个字节有特殊标记来表示后面有几个字节是该字符的一部分。而GBK编码格式每个汉字占两个字节。 在C语言中可以使用stdlib.h库函数中的mbstowcs()和wcstombs()来进行编码转换。mbstowcs()函数可以将一个字符串转换为宽字符数组,wcstombs()函数可以将宽字符数组转换为字符串。 将GBK编码格式的字符串转换为UTF-8格式需要进行如下操作: 1. 使用mbstowcs()函数将GBK字符串转换为宽字符数组。 2. 遍历宽字符数组,使用wcstombs()函数将每个宽字符(即一个汉字或一个英文字母)转换为UTF-8格式的字节。 3. 将所有转换后的字节组合成一个字符串即为UTF-8格式的字符串。 将UTF-8编码格式的字符串转换为GBK格式也需要进行类似的操作: 1. 使用mbstowcs()函数将UTF-8字符串转换为宽字符数组。 2. 遍历宽字符数组,使用wcstombs()函数将每个宽字符(即一个汉字或一个英文字母)转换为GBK格式的字节。 3. 将所有转换后的字节组合成一个字符串即为GBK格式的字符串。 需要注意的是,在进行编码转换时可能会出现一些字符无法转换的问题,处理方式可以选择忽略该字符或将该字符替换为一个特定字符。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值