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++程序库便有了大幅扩 ...
随机推荐
- ART、JIT、AOT、Dalvik之间有什么关系?
JIT与Dalvik JIT是"Just In Time Compiler"的缩写,就是"即时编译技术",与Dalvik虚拟机相关. 怎么理解这句话呢?这要从A ...
- Android 对.properties文件的读取
/** * * @param filepath .properties文件的位置 */ public void checkFileExists(String filepath){ File file ...
- 可以左右移动横向无缝滚动的JS图片展示代码
在酷站网站下的,具体路径忘了,稍微改了一下,让它看起来像组滑动 1)被引用的js文件ScrollPic.js ?){){i+=l.length;)I=document.cookie.length;o= ...
- mongdb aggregate 聚合数据
最近用到的一些mongodb的数据查询方法 及api用法 Aggregate() 数据聚合处理的方法 可以将聚合的一些方法放在其后面的括号中,也可继续以agg.的样式链式加入 aggregate.al ...
- 0-1分布(伯努利分布)、n 重伯努利分布(二项分布)
1. 0-1 分布(伯努利分布) 0-1分布又名两点分布,或叫伯努利分布. P{X=k}=pk(1−p)1−k 其中 k=0,1. 伯努利分布未必一定是 0-1 分布,也可能是 a-b 分布,只需满足 ...
- 【狼窝乀野狼】Parallel浅尝辄止
前段时间看到园子里面有同学在用Parallel进行批量插入数据库.后面也有很多同学针对这一事件给出了自己的看法和见解.我在这里不评论内容的好坏,至少能将自己东西总结分享这个是要靠勇气和毅力. 闲话少说 ...
- python 教程 第十三章、 特殊的方法
第十三章. 特殊的方法 1) 特殊的方法 __init__(self,...) 这个方法在新建对象恰好要被返回使用之前被调用. __del__(self) 恰好在对象要被删除之前调用. __st ...
- python 教程 第八章、 第一个python程序
第八章. 第一个python程序 #!/usr/bin/env python import os import sys import time source = [r'G:\s1', r'G:\s2' ...
- WPF自定义控件 使用阿里巴巴图标
原文:WPF自定义控件 使用阿里巴巴图标 上一篇介绍了 WPF自定义控件 按钮 的初步使用,在进一步介绍WPF自定义控件 按钮之前,先介绍一下如何在WPF项目中使用阿里巴巴图标,方便以后做示例. 1. ...
- 索引Index
优缺点 索引是对数据库表中一列或多列的值进行排序的一种结构为了提高查询的效率索引一般建立在需要经常查询的地方 优点 创建索引可以大大提高系统的性能第一,通过创建唯一性索引,可以保证数据库表中每一行数据 ...