C++的标准库函数默认都是操作字节,而不是字符,非常痛苦,所以引入了u16string和u32string(Linux上的wchar_t是32位的原因,utf16对unicode的支持是有缺陷的)good
时至今日,字符串使用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的更多相关文章
- 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_ ...
- 是否升级IOS11?IOS11不支持32位程序 查看手机哪些APP不支持
查看苹果32位APP具体步骤:设置-通用-关于本机-应用程序.如果手机中下载了32位应用的话,苹果会给出应用兼容性提醒:如果手机里没有安装32位应用,右侧没有小三角,点击“应用程序”也会没有反应. I ...
- C89标准库函数手册(待整理)
http://zh.cppreference.com/w/c 前言 ANSI C(C89)标准库函数共有15个头文件.这15个头文件分别为: 1.<assert.h> ...
- 设置联想键盘恢复F1~F12默认按键的操作办法
背景 默认都是笔记本键盘才有Fn组合功能键,台式机很少有.今天领到的是联想键盘,给我的台式机使用后F12很麻烦,必须Fn+F12才可以. 需求 恢复默认的F1~F12功能 方案 只需要下载驱动安装: ...
- C89标准库函数手册
http://zh.cppreference.com/w/c 前言 ANSI C(C89)标准库函数共有15个头文件.这15个头文件分别为: 1.<assert.h> ...
- 范围for语句 && 列表初始值&& 标准库函数begin和end
范围for语句: 引入的意义:简化传统for的编写,主要用于遍历给定序列中的每个元素并对序列中的每个值执行某种操作,其语法形式是: for( 声明: 给定序列) { 执行的操作. } 其中,“给定序列 ...
- C/C++语言的标准库函数malloc/free与运算符new/delete的区别
概括地说 1.malloc与free是C++/C的标准库函数,new/delete是C++的运算符,它们都可用于申请动态内存和释放内存. 2.对于非内部数据类型的对象而言,只用malloc/free无 ...
- C++/C语言的标准库函数与运算符的区别new/delete malloc/free
malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符.它们都可用于申请动态内存和释放内存.下面来看他们的区别. 一.操作对象有所不同 malloc与free是C++ ...
- C++ - 常用的标准库函数
写在前面 C++是一门博大精深的语言,也是最难学的一门编程语言,每一位励志学好C++的程序员都需要从基本功开始,稳扎稳打. 自从1998年C++ standard定案以后,C++程序库便有了大幅扩 ...
随机推荐
- Lettcode_104_Maximum Depth of Binary Tree
本文研究的总结,欢迎转载,但请注明出处:http://blog.csdn.net/pistolove/article/details/41964475 Maximum Depth of Binary ...
- 读取和修改xml文件
如有一个xml文件DownData.xml,内容如下 <?xml version="1.0" standalone="yes"?> <Root ...
- Spring Boot with JSP and Tiles3
Spring Boot with JSP and Tiles3 Using tiles and jsp on a Spring Boot 1.2.7 project file: pom.xml und ...
- javascript 中英文字符长度和截断处理
因:javascript中的String类自带的length属性 和 substr()方法虽然能判断和截取出字符个数,但是对字节个数却没有处理的方法(众所周知,中文字符占两个字节,英文只占一个) 果: ...
- 放大缩小,只需要使用这2个函数:SetWindowExtEx、SetViewportExtEx
相似函数: ScaleWindowExtEx.ScaleViewportExtEx 本例效果图: 代码文件: unit Unit1; interface uses Windows, Message ...
- 改变TLabel字型和颜色(Styled特性高于自身特性,李维的博客)
最近收到几位使用者的来信都是和如何改变FireMonkey TLabel组件的字型和颜色, 这几位使用者都是直接改变TextSettings特性中的Font子特性但却无法改变字型和颜色, 因此来信询问 ...
- WPF中用于嵌入其他进程窗口的自定义控件(AppContainer)
原文:WPF中用于嵌入其他进程窗口的自定义控件(AppContainer) 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199 ...
- CountDownLatch和CyclicBarrier 专题
4.Runnable接口和Callable接口的区别 有点深的问题了,也看出一个Java程序员学习知识的广度. Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行ru ...
- U3D游戏开发商思考
代码驱动带来的技术题 游戏碎片化.U3D 引擎有个非常有力的特色,就是实时编译执行.这意味着不管在不论什么时候,仅仅要按下执行图标,当前的场景就会进入可执行状态. 这导致了游戏在开发的过程中常常陷入一 ...
- 从Windows系统服务获取活动用户的注册表信息(当前活动用户的sessionId. 当前活动用户的 hUserToken)
首先,对“活动用户”的定义是,当前拥有桌面的用户.对于Windows XP及其以后的系统,即使是可以多个用户同时登录了,拥有桌面的也仅仅只有一个. 如果系统级服务调用Windows API来获取注册表 ...