汉字在 UTF-8 里是怎么编码的?
2025-08-15 20:51:16
发布于:广东
今天我突然想到,既然 char 只能储存 −128∼128 之间的字符,那么平时 string 是怎么可以存储汉字的呢?
我们随便输出一个字看看是什么情况。
freopen("1.out","w",stdout);
std::string s="神";
std::cout<<s;
打开 1.out,发现文件的编码是这样的:
E7 A5 9E
看来汉字是通过多个字节合成的。但是这引入了另一个问题:我从小到大学的都是存汉字要两个字节,到这里怎么变成三个了呢?这和 UTF-8 编码的存储有关系。
UTF-8 中,每个字符都用两个字节去存储,在纯使用 ASCII 字符的时候会显得比较浪费,因为使用了两倍的空间。
所以 UTF 就搞出了一种方案,让 ASCII 里的字符还是一个字节存储,但是这样计算机就不知道怎么分割了,所以 UTF 规定对于更长的字符,如果要占用 i 个字节,那么第一个字节前 i 个字符都是 1,第 i+1 个字符是 0。后面每个字节都以 10 开头。剩下的的部分放字符的编码。举几个例子:
对于字符 é(U+00E9),其编码就是 11000011 10101001。
对于字符 神(U+795E),其编码就是 11100111 10100101 10011110。
对于字符 𝄞(U+1D11E),其编码就是 11110000 10011101 10000100 10011110。
黑色的就是字符原来的编码。
这就是 UTF 中存储字符的方式了,现在我打算干一些神秘的东西,如果把格式故意改错,记事本里会显示什么呢?
freopen("1.out","w",stdout);
std::string s;s.resize(8);
s[0]=0xE6,s[1]=0x88,s[2]=0x91;
s[3]=0xE7,s[4]=0x88,s[5]=0xB1;
s[6]=0xE4,s[7]=0xBD;//s[8]=0xA0;
std::cout<<s;
输出:
鎴戠埍浣
看得出来我们一开始想输出 我爱你,但是删掉最后一个之后变成了乱码,这是什么原理呢?其实是记事本发现 UTF-8 格式不对,就使用 GBK 之类严格两个字节表示一个汉字的编码来直接解析了。如果你在终端中中文输出乱码,也是这个原理,只需要统一你终端和 IDE 的编码格式就可以了。
全部评论 4
顶
2025-08-16 来自 广东
0有点意思
2025-08-16 来自 浙江
0逆如天,真的有人会注意这个吗
2025-08-15 来自 浙江
0顶
2025-08-15 来自 广东
0
有帮助,赞一个