Unicode 随想

原创 2008年01月11日 06:48:00

最近 CodeGear 的工程师开始谈论[1][2][3][4][5] Delphi 全面支持 Unicode 的问题了。尽管这个是十年前的新闻,但对于 Delphi 的粉丝来说,迟到总比不到要强。本文是我对目前 Unicode 封装计划的一些看法。

 
现状

如果你不了解 AnsiString 和 WideString,请先去网上查阅相关资料。微软的 Visual C++ 在提供 Unicode 方案的时候,提供了一套宏机制[6]。在 Delphi 中也有类似的方法,比如大家最熟悉的 string/Char/PChar。

类型/函数别名
未使用编译指令 UNICODE
使用编译指令 UNICODE[7]
string
AnsiString
WideString
Char
AnsiChar
WideChar
PChar
PAnsiChar
PWideChar
GetCommandLine
GetCommandLineA
GetCommandLineW
 

宽字节版的字符串类型和 Windows API 函数很早就出现在 Delphi 中了。只是类型/函数别名一直只是对应到了传统的单字节版本上。简单来说,我们需要的是自由将类型/函数别名对应到单字节或者宽字节版本的数据类型上。

很多人想必和我一样对“程序全面支持 Unicode这个概念懵懵懂懂。这里所谓的支持,并不是说要让应用程序既可以在 Windows9x 上运行,又可以在 WindowsXP 上显示 Unicode 字符。而是指一个应用程序应该针对 Windows9x 和WindowsXP 分别编译单字节或者宽字节版本。

“一版通杀”的解决方案比较的累人。首先,字符串相关的数据类型在程序内部都是以宽字节版本定义的。当在 Windows9x 上调用 Windows API 的时候,开发者必须手动进行类型转换。这种做法费时费力,维护的工作量相当大。目前 Delphi 制作的兼容 Unicode 的应用程序,基本都采用这个方法。在此,要特地感谢一下牺牲最大的先驱 Troy 和他的 TntControl[8]。

比较可以接受的方案是编译二个版本。这样就的项目可以继续以 Ansi 模式顺利编译。而新的项目,只要遵循国际化编程准则的,也都可以成功的编译出单字节或者宽字节版本。尽管在处理宽字节 Windows API 函数的时候你需要加倍小心,比如有些数据类型要求字符串指针包含二个 #0结束符,但比起“一版通杀”的工作量,你真的要偷笑了。

我实在不明白,究竟CodeGear 叫苦了10年的 Unicode 的瓶颈到底在哪里?难道他们之前一直在往“一版通杀”的方向努力?

 
UnicodeString  vs  WideString

现有的 WideString (D4-D2007) 类型是个比较奇怪的东西。不同于 AnsiString,它为了兼容 COM 调用中常用的BSTR 类型,违背了引用计数原则。因此它就性能而言,完全无法与 AnsiString 相提并论[9]。想必是为了保证现有的项目能顺利在 Delphi2008 (codename Tiburon) 中通过,下个版本并不打算改造现有的 WideString,而是另起炉灶,引入一个新的类型 UnicodeString。我个人是强烈反对这个方案的。请看下面的表格

类型别名
单字节版本
宽字节版本
string
AnsiString
UnicodeString
Char
AnsiChar
WideChar
PChar
PAnsiChar
PWideChar
 

显而易见,UnicodeString 这个名字和 WideChar/PWideChar 是不一致的。我的想法是:CodeGear 应该把现有的WideString (D4-D2007) 命名成 BSTR,然后再引入一个全新的 WideString (即 UnicodeString) 以及一个新的类型别名 T_BSTR。

类型别名
未使用编译指令 UNICODE
使用编译指令 UNICODE[7]
string
AnsiString

WideString (UnicodeString)

Char
AnsiChar
WideChar
PChar
PAnsiChar
PWideChar
T_BSTR

WideString (D4-D2007)

BSTR
 

当你以单字节方式编译你的现有项目时,一切照旧,程序顺利编译。当你以宽字节方式编译同样的项目时,编译器会在 BSTR 被强制转换成新的 WideString 发出警告或者错误提示。并要求开发者认真考虑是使用 BSTR 还是 WideString。

CodeGear 的工程师们,你们要三思后行。以前你们已经错过一次,现在不能一错再错啊!
 
UTF-8  vs  UTF-16

UTF-16 肯定好过 UTF-8。原因很简单,UTF-8 是一种给单字节系统提供双字节支持的权宜之计[10]。尽管它使用了可变长度定义一个字符,节约了部分的内存空间,但是它在编码和解码上需要花费更多的时间。一来一去,你说谁更加划算呢?

 
Windows API 转换

正如 Delphi 的首席构架师 Allen[4] 所说,Windows API 函数别名会和 UnicodeString 一样被很好的处理。不过我希望今后的 Delphi 能有一种函数重定向指令,以方便开发者定义自己的单字节和宽字节函数版本。例如:

 {$IFDEF UNICODE}
    GetCommandLine mapping GetCommandLineA;
 {$ELSE}
    GetCommandLine mapping GetCommandLineW;
 {$ENDIF}
 
总结

在全面支持 Unicode 的过程中,确实会面临很多问题。既然微软在十年前就已经成功的解决了此问题,相信 CodeGear 的工程师不可能在今时今日仍然愁眉不展吧。让你的应用程序顺利支持 Unicode,你准备好了吗?

 
参考资料
[1] http://chrisbensen.blogspot.com/2007/11/unicode.html
[2] http://chrisbensen.blogspot.com/2007/11/unicode-sizeof-is-different-than-length_15.html
[3] http://chrisbensen.blogspot.com/2007/11/unicode-sizeof-is-different-than-length.html
[4] http://blogs.codegear.com/abauer/2008/01/09/38845
[5] http://blogs.codegear.com/abauer/2008/01/09/38846
[6] http://msdn2.microsoft.com/en-us/library/c426s321(VS.80).aspx
[7] 该编译指令目前仍然不可用。
[8] http://www.tmssoftware.com/tmsuni.htm
[9] http://tobias.feedian.com/2007/05/24/whats-wrong-with-delphis-widestring/
[10] http://en.wikipedia.org/wiki/Utf8
 
点击这里查看本文的英文版本
 

编程随想(更2015.11.13)

编程随想多模块交互模式思考三种模式 网络模式 每个模块都是同等地位,交互式是直接和其他模块交互。模块内封装发送操作和接受处理,并且配置信息发送的路由。 优势:与其他模块直接交互,效率高。 劣势:多模...
  • wctstc
  • wctstc
  • 2015年11月05日 17:32
  • 539

阿里前端两年随想

其实按照我的情怀和尿性,文章的标题应该是 前端登堂入室宝典、前端成长就这三招 之类,奈何这是篇软文 ~ 看官先别急Command + W,尤其是和我经历类似 做着其它岗位的工作,却多少会接...
  • mingqingyuefeng
  • mingqingyuefeng
  • 2017年04月28日 15:50
  • 150

个人总结感想系列 - 2014年总结

今天是2014年最后一天,做一个总结和复盘过去的一年。 学习和成长: 1. Java学习方面。 书籍:《java核心技术卷1》《java核心技术2》(部分),《Maven实战》《深入理解Java虚拟机...
  • initphp
  • initphp
  • 2014年12月31日 20:27
  • 2041

2014年感悟:一万年太久,只争朝夕

听着beyond的《真的爱你》,深夜闲暇 之余看了柴静的节目《看见--专访星爷》,感动之余依稀看到了些自己的身影:一万年太久,只争朝夕。回想自己的两个生肖轮回已悄然逝去,一次次深夜独处,一次次心灵感悟...
  • Eastmount
  • Eastmount
  • 2015年03月01日 02:26
  • 2648

Unicode字符列表

代码 显示 描述 U+0020 空格 U+0021 ! 叹号 U+0022 " 双引号 U+0023 # 井号 U+0024 $ 价钱/货币符号 U+0025 % ...
  • saycheesenn
  • saycheesenn
  • 2016年10月28日 10:26
  • 1045

【整理】ANSI和UNICODE字符串处理函数

字符串处理函数常用函数对照 ANSI UNICODE 通用 说明 数据类型 (char.h) (wchar.h) (tchar.h)   cha...
  • chenzy945
  • chenzy945
  • 2016年07月17日 10:41
  • 2312

unicode编码规则

一、Unicode与UTF-8之间的的关系 Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。 比如“二”字的unicode十六进制编码是:“4E8C...
  • u014200359
  • u014200359
  • 2014年04月13日 20:53
  • 2252

MFC与unicode的纠结

关于MFC的小总结
  • w417950004
  • w417950004
  • 2015年09月17日 20:31
  • 920

按行读取ANSI、UNICODE 、UNICODE big endian、UTF-8四种文本文

代码简介 1.问题提出 MFC提供的文件类CStdioFile,其中一个函数ReadString实现了文件的按行读取,但是不能满足不同类型的文本文件的按行读取,为了解决这一问题,笔者初步研究了一些...
  • sky101010ws
  • sky101010ws
  • 2016年06月20日 16:35
  • 1671

特殊符号 UNICODE编码

⇠  箭头类 符号 UNICODE 符号 UNICODE HTML JS CSS HTML JS CSS ...
  • Tectool
  • Tectool
  • 2016年06月03日 12:22
  • 14966
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Unicode 随想
举报原因:
原因补充:

(最多只允许输入30个字)