时至今日,字符串使用unicode已经是不需要理由的常识,但对一些有着悠久历史的编程语言来说,这仍然是个头痛的问题。如果抛开第三方库的支持,C++其实并不能实际有效地支持unicode,即使是utf8。(注:本文讨论的是字符串在内存中的编码方案,而不是文件或网络数据流。)

STL的string模板诞生时,unicode还是理想中的固定16位编码。那时,Windows、Java等先后跨跃进unicode时代,而Unix/Linux受限于向后兼容而难以改变。那时Windows上的C++编程主要用用Win32 API,还不流行STL,而Unix/Linux上还基本不支持Unicode。STL的wstring,只是将char模板参数替换成wchar_t,看起来似乎完全合理,其实并没有经过实践检验。所以,Windows上的wstring至今一直处于实际上不可用的状态,各种IO时的编码转换都有问题;而Linux上的wchar_t是32位,太浪费内存所以完全不值得使用。(最新的标准针对unicode引入了char16_t和char32_t,以及u16string和u32string

为什么Linux上的wchar_t是32位呢?因为gcc开始支持宽字符的时候,大约也是unicode的字符集突破16位编码极限的时候。本来预期非常充足的码位,出乎意料的不够了,unicode不得不做出调整。调整后,有了三种可选的unicode编码:
    utf32:一个码位固定4字节,一个码位表示一个字符编码。
    utf16:兼容之前的16位编码,一个码位2字节,但1或2个码位表示一个字符编码(所以有可能会有问题)。
    utf8:兼容ASCII编码,一个码位1字节,但1到6个码位表示一个字符编码。(现行标准其实要求最多4个码位,但出于保障兼容性的原因,5、6个码位的情况是可能出现的,即使这算无效编码。)
    (除此之外,还有字符组合和修饰符组合的情况,使得码位到字符的映射更加复杂,在此忽略。)
    
utf8的出现,让Linux系统发现了新的机会,既然兼容ASCII,那么只要系统的编码页新加一个utf8的,不就支持unicode了么。很自然的,Linux就走了这条路。而Windows却不支持utf8的编码页,这让很多写跨平台程序的人对微软很是不满。而后,更有人宣称,Windows、Java、.NET等选错了unicode编码,utf8才是王道。

我很希望字符编码有个完美的解决方案,但很可惜,每当我们试图让它变得简单,它就变得更加复杂。最基本的问题:一个utf8编码的char数组,只不过是一个字节buffer,在C/C++的标准库支持下,你根本无法把它当字符串来处理。想要字符串长度?它只能给你字节数,而不是字符数。想要取第n个字符?它只能给你第n个字节。想要把一个字符转大写?想判断一个字符是否是字母?它只接受char类型的字符,也就是说只支持ASCII字符……

即使说对一个不需要操作字符的程序,在C/C++程序里我们总是要为输入分配buffer的,那么预期输入n个字符的buffer,应该分配多少字节呢?没错,你只能按最大可能n*6+1来分配。对内存临时分配还好,要是一个数据库字段,你怎么办?这时即使是utf32都可能更省存储空间。

当然,绝大多数问题都可以通过使用一个第三方的unicode库来解决。如果觉得专门的unicode库太heavy,至少还有boost的日常解决方案,只要把所有字符串操作替换成专门的函数……(如果安全性对你的程序很重要,你还要了解所用函数在遇到无效编码时的行为,因为这也是黑客突破安全检查的一种手段。)

但是,大多数的程序员甚至并不清楚unicode编码,更不可能了解编码转换的复杂性,他们或者习惯了C风格的字节操作,或者来自Java等使用双字节unicode的语言,做着并非字处理的软件,所以对学习复杂的unicode编码系统并无太大兴趣。所以,utf8在C/C++里,更象是专家级的解决方案,而并非面向普通开发者。理想情况下,C++可以凭借其强大的抽象和封装能力,包装出一个真正基于字符访问的字符串类(Python3走了这条路,但有很多批评的声音),然而现实中则很难将其标准化。

那么Windows、Java、.NET、iOS等所使用的utf16呢?本质上,他们的支持都是有缺陷的。因为他们开始时支持的其实是utf16的前身UCS2,每个字符固定2字节,而当utf16出现后,就权当UCS2用,也就是说双码位4字节的字符(unicode里称作BMP以外的字符)会被当作两个字符处理。如果你的程序真的想要正确支持双码位的字符,就要改写程序,使用高级字符串函数来访问字符串,而不是直接用下标索引。只是因为BMP以外的字符极其罕用,其程序员并不急需了解这些细节。从正确性角度来说,这并不正确,但从实用角度来说,还算实用。

http://blog.csdn.net/nightmare/article/details/39780931#comments

C++的标准库函数默认都是操作字节,而不是字符,非常痛苦,所以引入了u16string和u32string(Linux上的wchar_t是32位的原因,utf16对unicode的支持是有缺陷的)good的更多相关文章

  1. wchar_t是内置还是别名(亲测有效:wchar_t在windows下是16位整数的别名,在linux等平台下是32位整数的别名。MSVC2008开始默认是/Zc:wchar_t)

    接前一篇C++ ABI之名字改编(以Qt为例),继续看看C++名字改编相关的问题. 问题 MSVC 有一对选项/Zc:wchar_t- 与 /Zc:wchar_t控制wchar_t 于是 wchar_ ...

  2. 是否升级IOS11?IOS11不支持32位程序 查看手机哪些APP不支持

    查看苹果32位APP具体步骤:设置-通用-关于本机-应用程序.如果手机中下载了32位应用的话,苹果会给出应用兼容性提醒:如果手机里没有安装32位应用,右侧没有小三角,点击“应用程序”也会没有反应. I ...

  3. C89标准库函数手册(待整理)

    http://zh.cppreference.com/w/c 前言 ANSI C(C89)标准库函数共有15个头文件.这15个头文件分别为: 1.<assert.h>            ...

  4. 设置联想键盘恢复F1~F12默认按键的操作办法

    背景 默认都是笔记本键盘才有Fn组合功能键,台式机很少有.今天领到的是联想键盘,给我的台式机使用后F12很麻烦,必须Fn+F12才可以. 需求 恢复默认的F1~F12功能 方案 只需要下载驱动安装: ...

  5. C89标准库函数手册

    http://zh.cppreference.com/w/c 前言 ANSI C(C89)标准库函数共有15个头文件.这15个头文件分别为: 1.<assert.h>            ...

  6. 范围for语句 && 列表初始值&& 标准库函数begin和end

    范围for语句: 引入的意义:简化传统for的编写,主要用于遍历给定序列中的每个元素并对序列中的每个值执行某种操作,其语法形式是: for( 声明: 给定序列) { 执行的操作. } 其中,“给定序列 ...

  7. C/C++语言的标准库函数malloc/free与运算符new/delete的区别

    概括地说 1.malloc与free是C++/C的标准库函数,new/delete是C++的运算符,它们都可用于申请动态内存和释放内存. 2.对于非内部数据类型的对象而言,只用malloc/free无 ...

  8. C++/C语言的标准库函数与运算符的区别new/delete malloc/free

    malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符.它们都可用于申请动态内存和释放内存.下面来看他们的区别. 一.操作对象有所不同 malloc与free是C++ ...

  9. C++ - 常用的标准库函数

      写在前面 C++是一门博大精深的语言,也是最难学的一门编程语言,每一位励志学好C++的程序员都需要从基本功开始,稳扎稳打. 自从1998年C++ standard定案以后,C++程序库便有了大幅扩 ...

随机推荐

  1. Docker + .NET Core(三)-两种发布方式

    原文:Docker + .NET Core(三)-两种发布方式 第一种,自己手写dockerfile发布,上传至hubDocker 正常发布到文件夹中,发布文件上传至linux机器上.如 /www/a ...

  2. hadoop 集群及hbase集群的pid文件存放位置

    一.当hbase集群和hadoop集群停了做一些配置调整,结果执行stop-all.sh的时候无法停止集群, 提示no datanode,no namenode等等之类的信息, 查看stop-all. ...

  3. cocos2d-x创建第一个项目

    #include "AppDelegate.h" #include "HelloWorldScene.h" USING_NS_CC; AppDelegate:: ...

  4. 经典书单 —— 语言/算法/机器学习/深度学习/AI/CV/PGM

    0.0 计算机科学 <Lex 与 Yacc> Think Complexity(使用 Python 语言) GitHub - AllenDowney/ThinkComplexity: Co ...

  5. 部署NetCore项目(本文介绍用用IIS部署)

    首先要下载安装Core Runtim: 然后在IIS中的模块中就可以看到如下内容: 这时环境就搭好了: 下面按照正常的发布流程走就行了,关键看下面(一定要选择无托管代码)

  6. hadoop编程技巧(6)---处理大量的小型数据文件CombineFileInputFormat申请书

    代码测试环境:Hadoop2.4 应用场景:当需要处理非常多的小数据文件,这种技术的目的,可以被应用到实现高效的数据处理. 原理:申请书CombineFileInputFormat,能够进行切片合并的 ...

  7. Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产(使用cef 内核)

    Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产 Go 在服务端的优势不容置疑,但是在桌面应用上却没有好的 GUI 支持,本项目是 Go 语言在 Windows 上 ...

  8. 扩展你的javascript数组

    如今做的项目用的正是jquery的框架,Jquery miniui,其功能强大.性能卓越.易于上手.不失灵活,在不断学习和研发的过程中,miniui给了非常多的启示,让我又一次认识了js的本质,意识到 ...

  9. PHP关联数组教程

    PHP 数组 关联数组 什么是数组?在使用 PHP 进行开发的过程中,或早或晚,您会需要创建许多相似的变量.无需很多相似的变量,你可以把数据作为元素存储在数组中.数组中的元素都有自己的 ID,因此可以 ...

  10. mybatis 使用经验小结 good

    一.多数据源问题 主要思路是把dataSource.sqlSesstionFactory(用来产生sqlSession).MapperScannerConfigurer在配置中区分开,各Mapper对 ...