C:汉字存储
问题
C语言中汉字如何存储?梳理思路!
答案
在计算机中,一个英文字符占1个字节,汉字占两个字节,如果用char字符数组存储字符时,需要在最后面自动加上一个字节的结束符“\0”
汉字转进制输出
比如:
//英文字符,占4个字节 char Info[] = "abc"; printf("%s\n",Info); printf("Info长度:%d\n",sizeof(Info)); //中文,占5个字节 char Han[]="中国"; printf("%s\n",Han); printf("Han长度:%d\n",sizeof(Han));
不同的编码方式,汉字存储的字节数量不同,比如:
GB2312编码:一个汉字两个字节
UTF-8编码: 一个汉字三个字节
GBK编码:一个汉字两个字节
UTF-16:一个汉字3个字节
GB2312 --> GBK --> GB18030 是中文编码的三套方案,出现的时间从早到晚,收录的字符数目依次增加,并且向下兼容。GB2312 和 GBK 收录的字符数目较少,用 1~2个字节存储;GB18030 收录的字符最多,用1、2、4 个字节存储。
1) 从整体上讲,GB2312 和 GBK 的编码方式一致,具体为:
- 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0,这和 ASCII 编码是一致的,所以说 GB2312 完全兼容 ASCII。
- 对于中国的字符,使用两个字节存储,并且规定每个字节的最高位都是 1。
例如对于字母A
,它在内存中存储为 01000001;对于汉字中
,它在内存中存储为 11010110 11010000。由于单字节和双字节的最高位不一样,所以字符处理软件很容易区分一个字符到底用了几个字节。
2) GB18030 为了容纳更多的字符,并且要区分两个字节和四个字节,所以修改了编码方案,具体为:
- 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0,这和 ASCII、GB2312、GBK 编码是一致的。
- 对于常用的中文字符,使用两个字节存储,并且规定第一个字节的最高位是 1,第二个字节的高位最多只能有一个连续的 0(第二个字节的最高位可以是 1 也可以是 0,但是当它是 0 时,次高位就不能是 0 了)。注意对比 GB2312 和 GBK,它们要求两个字节的最高位为都必须为 1。
- 对于罕见的字符,使用四个字节存储,并且规定第一个和第三个字节的最高位是 1,第二个和第四个字节的高位必须有两个连续的 0。
例如对于字母A
,它在内存中存储为 01000001;对于汉字中
,它在内存中存储为 11010110 11010000;对于藏文གྱུ
,它在内存中的存储为 10000001 00110010 11101111 00110000。
字符处理软件在处理文本时,从左往右依次扫描每个字节:
- 如果遇到的字节的最高位是 0,那么就会断定该字符只占用了一个字节;
- 如果遇到的字节的最高位是 1,那么该字符可能占用了两个字节,也可能占用了四个字节,不能妄下断论,所以还要继续往后扫描:
- 如果第二个字节的高位有两个连续的 0,那么就会断定该字符占用了四个字节;
- 如果第二个字节的高位没有连续的 0,那么就会断定该字符占用了两个字节。
可见,当字符占用两个或者四个字节时,GB18030 编码要检测两次,处理效率比 GB2312 和 GBK 都低。
GBK 于 1995 年发布,这一年也是互联网爆发的元年,国人使用电脑越来越多,也许是 GBK 这头猪正好站在风口上,它就飞起来了,后来的中文版 Windows 都将 GBK 作为默认的中文编码方案。
注意,这里我说 GBK 是默认的中文编码方案,并没有说 Windows 默认支持 GBK。Windows 在内核层面使用的是 Unicode 字符集(严格来说是 UTF-16 编码),但是它也给用户留出了选择的余地,如果用户不希望使用 Unicode,而是希望使用中文编码方案,那么这个时候 Windows 默认使用 GBK(当然,你可以选择使用 GB2312 或者 GB18030,不过一般没有这个必要)。
汉字编码输出
汉字编码并输出示例:
//汉字编码 unsigned char Han[]="中国"; printf("汉字:%s\n",Han); printf("十六进制:"); for(int i=0;i<4;i++) { printf("%X",Han[i]); } printf("\n十进制:"); for(int i=0;i<4;i++) { printf("%d",Han[i]); }
汉字编码输出存储
汉字编码存储示例:
//汉字编码存储 unsigned char Han[] = "中国"; FILE* fp = fopen("out.txt", "w");//输出 printf("汉字:%s\n", Han); fputs("十六进制:", fp); for (int i = 0; i < 4; i++) { fprintf(fp, "%X", Han[i]); } fseek(fp, 0, SEEK_END); fputs("\n十进制:", fp); for (int i = 0; i < 4; i++) { fprintf(fp, "%d", Han[i]); } fclose(fp);
汉字存储到数组
#include <stdio.h> #include <string.h> #define MAX_LINE 100 //每行最大字节数 void main() { unsigned char strLine[MAX_LINE]; int len = 0; FILE *fp = fopen("D:\\code\\vc\\C\\plaintext_keywords.txt", "r"); if(NULL == fp) { printf("failed to open dos.txt\n"); } while (!feof(fp)) { fgets(strLine,7,fp); printf("%s",strLine); } fclose(fp); printf("\n"); system("pause"); }
参考
1、汉字的存储