LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

UTF-8 vs UTF-16两种格式有何异同

admin
2025年4月19日 21:51 本文热度 125

之前,介绍了UTF-8UTF-16,实际上还有UTF-32这个名称就知道是什么意思了,因为应用不广,所以就不展开说了。

注:如果后面提到的一些细节,可能需要先看过,介绍UTF-16 和 介绍UTF-8
先说一个共同点:UTF-8和UTF-16都是变长编码,因为UTF-16是变长编码(每个字符为2字节或4字节)这事很少被提及。
看标题应该也能猜到,我们主要说的是UTF-8和UTF-16的差别。但在说这个之前,我们要考虑,程序真正使用的编码是什么?是Unicode吗?实际上并不会真的使用Unicode(除非是UTF-32),而是使用UTF-8或UTF-16等(这就和GB2312编码中真实使用的都是GB2312内码一样)
先考虑它们使用空间的差别。
UTF-16虽然是变长,但实际上Unicode基本多文种面(0号面)的使用频率非常高,这导致了UTF-6的编码长度基本等于字符数的2倍。
UTF-8编码中,一个字符长度为1~4字节不等(Unicode目前最长为21位,所以不会使用介绍的5~6字节)

  • 英文字母和数字都是1字节
  • 欧洲的拉丁字母等基本都是2字节
  • 中文等基本都是3字节
  • Unicode编码的1号面~16号面为4字节

这样实际上,UTF-8编码的一个字符基本是1~3字节,具体的使用概率应该和用户相关(就是用户主要使用那种语言)
我们知道:Windows操作系统使用的是UTF-16编码,Linux操作系统使用的是UTF-8编码。这里分析一下它们各自的选择逻辑,微软是为了卖给全世界的,所以它选择了UTF-16,例如,Java等也是使用了UTF-16。但Linux不同,它是开源的,早期的开发者都是欧美的,选择UTF-8使用的空间一定不比UTF-16差(哪怕是拉丁字母占比更多,也就是和UTF-16持平,只有中文等字符占比多的情况下才会出现UTF-16更优的)。
在使用的时候,有时需要UTF-8和UTF-16相互转换,因为它们有规律,是可以相互转换的。但是,如果需要GB18030和UTF-8相互转换,就没有可以终结的规律了。所以,这里就不介绍UTF-8和UTF-16相互转换的代码了,编码的相互转换可以使用iconv(参考附录三)
在源码的编码上,推荐使用UTF-8,此时使用MSVC编译,添加一个参数 /utf-8
传输协议的文本编码方案,要优先考虑兼容性,然后再考虑节省空间。
最后,说一下Windows上的编码问题,内核使用的是UTF-16编码,但很多API,都提供了A版和W版,例如,CreateFile这个API,实际上提供了CreateFileA和CreateFileW两个版本,而CreateFile实际上是一个宏。但是有个别API只有W版的,更有甚者,W版和A版的功能(或效果)不完全一致,所以,如果可以,尽量使用W版本的。
Windows的应用程序主要有两种(Console和Windows,VS界面设置里在Linker->SubSystem中)。Console的默认编码通常并不是UTF-16,中文系统默认为代码页936(这个可以看之前的文章,代码页GB2312GBK等),这个默认编码通常称为本地编码。本地编码和UTF-16的相互转化可以使用下面的系统API:

  • MultiByteToWideChar
  • WideCharToMultiByte

注意,这两个API的用法和iconv差异挺大的,微软的API文档很完整,这里就不展开了。非必要,Windows上不用iconv,这个看附录三。
附录:
附录一
Linux的编码使用UTF-8的一个好处,就是内核裁剪上有那么一点点优势----就是剪裁到嵌入式系统的层度。
附录二
关于信创系统的编码,目前基本都是UTF-8编码。我能想到的两个原因:
1. 修改系统层面的编码节省的空间和现在计算机硬件相比,实际上已经没那么重要了
2. 能够更大层度的兼容当前的软件。这里的兼容主要是指二进制的兼容,就是第三方软件不需要重新编译就可以运行。
附录三
关于iconv这个库,需要注意函数iconv,一共5个参数,第二和第三两个参数共同组成一个内存段(内存起点指针和长度)第四和第五两个参数共同组成一个内存段。它对内存段的使用有一点特别,都是传入传出参数(即是入参也是出参)。无论函数是否成功,内存段都会变为剩余的部分,举例,下面示例代码:
// 示例代码1
#include <iconv.h>

int main()
{
    // 编码转换的源编码文本
    constchar utf8[] = "幻想";
    // 转换后的编码的储存位置
    char buff[20] = { 0 };
    // in_size值是7, 如果使用strlen则是6,都可以
    size_t in_size = sizeof(utf8);
    // 这里是 UTF-8 转 GB2312
    iconv_t co = iconv_open( "GB2312""UTF-8");
    do {
        if (co == (iconv_t)(-1)) {
            // iconv_open失败
            break;
        }
        // 这里一定要使用一个新的指针变量,iconv函数不能直接使用变量 utf8
        // 因为 utf8 作为一个指针,是不能修改的,这不符合iconv的用法
        char* in_buff = (char*)(utf8);
        // 输出内存段的起始位置
        size_t out_size = sizeof(buff);
        // 这里也需要使用一个新的指针变量
        char* out_buff = (char*)(buff);
        // 在iconv执行前:
        // in_buff == utf8 而且 out_buff == buff
        size_t result = iconv(co, &in_buff, &in_size, &out_buff, &out_size);
        // 在iconv执行前:
        // in_buff != utf8 而且 out_buff != buff
        // 通常为 in_buff > utf8 而且 out_buff > buff
        // 并且 in_size 和 out_size 的值也会变小
        // -------------------
        // GB2312的编码结果存在的内存起点为 buff, 长度为 sizeof(buff) - out_size
        // result == (iconv_t)(-1) 为失败
    } while(false);
    if (co != (iconv_t)(-1)) {
        // 这里回收 iconv_open 的资源
        iconv_close(co);
    }
}
上面代码如果编译,记得链接iconv库
在linux和mac上,基本都是默认安装了iconv库的。如果在Windows上需要使用iconv,可以参考下面文档:
https://www.codeproject.com/Articles/302012/How-to-Build-libiconv-with-Microsoft-Visual-Studio


阅读原文:原文链接


该文章在 2025/4/21 10:32:56 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved