您的位置:首页 > 编程语言

Windows环境下Unicode编程总结

2010-04-06 15:58 337 查看
UNICODE
环境设置


安装
Visual Studio
时,在选择
VC++
时需要加

unicode

项,保证相关的库文件可以拷贝到
system32
下。

UNICODE
编译设置:

C/C++, Preprocessor difinitions
去除
_MBCS
,加
_UNICODE,UNICODE


ProjectSetting/link/output

中设置
Entry

wWinMainCRTStartup


之为
MBCS

ANSI
)编译。

Unicode
:宽字节字符集

1.

如何取得一个既包含单字
节字符又包含双字节字符的字符串的字符个数?


可以调用
Microsoft Visual C++
的运行期库包含函数
_mbslen
来操作多字节(既包括单字节也包括双字节)字符串。

调用
strlen
函数,无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的
0
之前有多少个字节。

2.

如何对

DBCS

(双字节字符集)字符串进行操作?


函数

描述

PTSTR CharNext

LPCTSTR

;
返回字符串中下一个字符的
地址

PTSTR CharPrev

LPCTSTR, LPCTSTR
);

返回字符串中上一个字符的地址

BOOL IsDBCSLeadByte( BYTE )


如果该字节是
DBCS
字符的第一个字节,
则返回非
0


3.

为什幺要使用

Unicode





1


可以很容易地在不同语言之间进行数据交换。


2


使你能够分配支持所有语言的单个二进制
.exe
文件或
DLL
文件。


3


提高应用程序的运行效率。

Windows 2000
是使用
Unicode
从头进行开发
的,如果调用任何一个
Windows
函数并给它传递一个
ANSI

符串,那幺系统首先要将字符串转换成
Unicode
,然后将
Unicode
字符串传递给操作系统。如果希望函数返回
ANSI
字符串,系统就会首先将
Unicode
字符串转换成
ANSI
字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头
开始用
Unicode
来开发应用程序,就能够使你的应用程序更加有效地运行。

Windows CE
本身就是使用
Unicode
的一种操作系统,完全不支持
ANSI Windows
函数

Windows 98
只支持
ANSI
,只能为
ANSI
开发应用程序。

Microsoft
公司将
COM

16

Windows
转换成
Win32
时,公司决定需要字
符串的所有
COM
接口方法都只能接受
Unicode
字符串。

4.

如何编写

Unicode

源代码?


Microsoft
公司为
Unicode
设计了
WindowsAPI
,这样,
可以尽量减少代码的影响。实际上,可以编写单个源代码文件,以便使用或者不使用

Unicode

来对它进行编译。只需要定义两个宏(

UNICODE



_UNICODE

),就可以修改然后重新编译该源文件。

_UNICODE

宏用于

C

运行期头文件,而

UNICODE

宏则用于

Windows

头文件。


编译源代码模块时,通常必须同时定义这两个宏。

5. Windows

定义的

Unicode

数据类型有哪些?


数据类型

说明

WCHAR Unicode
字符

PWSTR
指向
Unicode
字符串的指针

PCWSTR
指向一个恒定的
Unicode
字符串的指针

对应的
ANSI
数据类型为
CHAR

LPSTR

LPCSTR


ANSI/Unicode
通用数据类型为
TCHAR

PTSTR,LPCTSTR


6.

如何对

Unicode

进行操作?


字符集

特性

实例

ANSI
操作函数以
str
开头
strcpy

Unicode
操作函数以
wcs
开头
wcscpy

MBCS
操作函数以
_mbs
开头
_mbscpy

ANSI/Unicode
操作函数以
_tcs
开头
_tcscpy

C
运行期库)

ANSI/Unicode
操作函数以
lstr
开头
lstrcpy

Windows
函数)

所有新的和未过时的函数在
Windows2000
中都同时拥有
ANSI

Unicode
两个版本。
ANSI
版本函数结尾以
A
表示;
Unicode
版本函数结尾以
W
表示。
Windows
会如下定义:

#ifdef UNICODE

#define CreateWindowEx CreateWindowExW

#else

#define CreateWindowEx CreateWindowExA

#endif // !UNICODE

7.

如何表示

Unicode

字符串常量?


字符集

实例

ANSI “string”

Unicode L“string”

ANSI/Unicode T(

string

)

_TEXT(

string

)if( szError[0] ==
_TEXT(

J

) ){ }

8.

为什幺应当尽量使用操作
系统函数?


这将有助于稍稍提高应用程序的
运行性能,因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程
Explorer.exe
所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入
RAM


如:
StrCat

StrChr

StrCmp

StrCpy
等。

9.

如何编写符合

ANSI



Unicode

的应用程序?



1


将文本串视为字符数组,而不是
chars
数组或字节数组。


2


将通用数据类型(如
TCHAR

PTSTR
)用于文本字符和字
符串。


3


将显式数据类型(如
BYTE

PBYTE
)用于字节、字节指
针和数据缓存。


4



TEXT
宏用于原义字符和字符串。


5


执行全局性替换(例如用
PTSTR
替换
PSTR
)。


6


修改字符串运算问题。例如函数通常希望在字符中传递一个
缓存的大小,而不是字节。这意味着不应该传递
sizeof(szBuffer),
而应该传
递(
sizeof(szBuffer)/sizeof(TCHAR)
。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那幺请记住要按字节来分
配内存。这就是说,应该调用

malloc(nCharacters *sizeof(TCHAR)),
而不是调用
malloc(nCharacters)


10.

如何对字符串进行有选
择的比较?


通过调用
CompareString
来实现。

标志

含义

NORM_IGNORECASE
忽略字母的
大小写

NORM_IGNOREKANATYPE

区分平假名与片假名字符

NORM_IGNORENONSPACE

略无间隔字符

NORM_IGNORESYMBOLS
忽略
符号

NORM_IGNOREWIDTH
不区分单
字节字符与作为双字节字符的同一个字符

SORT_STRINGSORT
将标点符号
作为普通符号来处理

11.

如何判断一个文本文件是

ANSI

还是

Unicode




判断如果文本文件的开头两个字
节是
0xFF

0xFE
,那幺就是
Unicode
,否则是
ANSI


12.

如何判断一段字符串是

ANSI

还是

Unicode





IsTextUnicode
进行判断。
IsTextUnicode
使
用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此
IsTextUnicode
有可能返回不正确的结果。

13.

如何在

Unicode



ANSI

之间转换字符串?


Windows
函数
MultiByteToWideChar
用于将多字节字符串转换成宽字符串;函数
WideCharToMultiByte
将宽字符串转换成等价的多字节字符串。

14.

Unicode



DBCS

之间的区别


Unicode
使用(特别在
C
程序设计语言环境里)“宽字符集”。「
Unicode
中的每个字符都是
16
位宽而
不是
8
位宽。」在
Unicode
中,没有单单
使用
8
位数值的意义存在。相比之下,在“双位组字符集”中我们仍然处理
8
位数值。有些位组自身定义字符,而某些位组则显示需要和另一个位组共同定义一个字符。

处理
DBCS
字符串非常杂乱,但是处理
Unicode
文字则像处理有秩序的文字。您也许会高兴地知道前
128

Unicode
字符(
16
位代码从
0x0000

0x007F
)就是
ASCII
字符,而接下来的
128

Unicode
字符(代码从
0x0080

0x00FF
)是
ISO 8859-1

ASCII
的扩展。
Unicode
中不同部分的字
符都同样基于现有的标准。这是为了便于转换。希腊字母表使用从
0x0370

0x03FF
的代码,斯拉夫语使用从
0x0400

0x04FF
的代码,美国使用从
0x0530

0x058F
的代码,希伯来语使用从
0x0590

0x05FF
的代码。中国、日本和韩国的象形文字(总称为
CJK
)占用了从
0x3000

0x9FFF
的代码。
Unicode
的最大好处是这
里只有一个字符集,没有一点含糊。

15.

衍生标准


Unicode

是一个标准。
UTF-8

是其概
念上的子集,
UTF-8

是具体的编码标准。而UNICODE是所有想达到世界统一编码标准的标准。
UTF-8

标准就是
Unicode


ISO10646

)标准的一种变形方式,

UTF
的全
称是:
Unicode/UCS
Transformation Format
,其实有两种
UTF
,一种是
UTF-8
,一种是
UTF-16


不过
UTF-16
使用较少,其对应关系如下:


Unicode
中编码为
0000 - 007F

UTF-8
中编码形式为
: 0xxxxxxx


Unicode
中编码为
0080 - 07FF

UTF-8
中编码形式为
: 110xxxxx 10xxxxxx


Unicode
中编码为
0000 - 007F

UTF-8
中编码形式为
: 1110xxxx 10xxxxxx 10xxxxxx

utf-8

unicode
的一个新的编码标准
,
其实
unicode
有过好几个标准
.
我们知道
一直以来使用的
unicode
字符内码都是
16

,
它实际上还不能把全世界的所有字符编在一个平面系统
,
比如中国的藏文等小语种
,
所以
utf-8
扩展到了
32

,
也就是说理论在
utf-8

可容纳二的三十二次方个字符
. UNICODE
的思想就是想把所有的字符
统一编码
,
实现一个统一的标准
.big5

gb
都是独立的字符集
,
这也叫做
远东字符集
,
把它拿到德文版的
WINDOWS
上可能将会引起字符编码的冲突
....
早期的
WINDOWS
默认的字符集是
ANSI.notepad
中输入的汉字是本地编码
,
但在
NT/2000
内部是可以直接支持
UNICODE
的。
notepad.exe

WIN95

98
中都是
ANSI
字符
,

NT
中则是
UNICODE.ANSI

UNICODE
可以方便的实现
对应映射
,
也就是转换
ASCII

8
位范围内的字符集,对于范围之外的字符如汉字它是无法表达的。
unicode

16
位范围内的字符集,对于不
同地区的字符分区分配,
unicode
是多个
IT
巨头共同制定的字符编码标
准。如果在
unicode
环境下比如
WINDOWS NT
上,一
个字符占两字节
16
位,而在
ANSI
环境下如
WINDOWS98
下一个字符占一个字节
8

.Unicode
字符是
16
位宽,最多允许
65,535
字符,数据类型被称为
WCHAR


对于已有的
ANSI
字符,
unicode
简单的将其扩展

16
位:比如
ANSI"A"=0x43,

对应的
UNICODE


"A"= 0x0043


ASCII
用七存放
128
个字符
,ASCII
是一个真正的美国标准
,
所以它不
能满足其他国家的需要
,
例如斯拉夫语的字母和汉字于是出现了
Windows ANSI
字符集
,
是一种扩展的
ASCII

,

8
位存放字符
,

128
位仍然存放原来的
ASCII

,

而高
128
位加入了希腊字母等

if def UNICODE

TCHAR = wchar

else

TCHAR = char

你需要在
Project/Settings/C/C++/Preprocesser
definitions
中添加
UNICODE

_UNICODE

UINCODE,_UNICODE
都要定义。
不定义
_UNICODE
的话,用
SetText(HWND,LPCTSTR),
将被解释为
SetTextA(HWND,LPTSTR),
这时
API
将把你给的
Unicode
字符串看作
ANSI
字符串,显示乱码。因

windows
API
是已经编译好存在于
dll
中的,由于不管
UNICODE
还是
ANSI
字符串,都被看作一段
buffer,

"0B
A3 00 35 24 3C 00 00"
如果按
ANSI
读,因为
ANSI
字串是以
'/0'
结束的,所以只能读到两字节
"0B A3 /0"
,如果按
UNICODE
读,将完整的读到
'/0/0'

束。

由于
UNICODE
没有额外的指示位,所以系统必须知道你提供的字串是哪种格式。此外,
UNICODE
好象是
ANSI C++
规定的,
_UNICODE

windows SDK
提供
的。如果不编写
windows
程序,可以只定义
UNICODE


开发过程:

围绕着文件读写、字符串处理展
开。文件主要有两种:
.txt

.ini
文件

1.


unicode
和非
unicode
环境下字符串做
不同处理的,那么需要参考以上
9

10
两条,以适应不同环境得字符串处理要求。

对文件读写也一样。只要调用相
关接口函数时,参数中的字符串前都加上
_TEXT
等相关宏。如果写成的那个文件需要是

unicode
格式保存的,那么在创建文件时需要加入一个字节头。

CFile

file
;

WCHAR

szwBuffer
[
128

];

WCHAR
*
pszUnicode
= L
"Unicode string/n"
;
// unicode string

CHAR
*
pszAnsi
=
"Ansi string/n"
;
// ansi string

WORD

wSignature
=
0xFEFF

;

file
.
Open
(
TEXT
(
"Test.txt"
),
CFile
::
modeCreate
|
CFile
::
modeWrite

);

file
.
Write
(&
wSignature
,
2

);

file
.
Write
(
pszUnicode
,
lstrlenW
(
pszUnicode
) *
sizeof
(
WCHAR

));

//
explicitly use lstrlenW function

MultiByteToWideChar
(
CP_ACP
,
0
,
pszAnsi
, -
1
,
szwBuffer
,
128

);

file
.
Write
(
szwBuffer
,
lstrlenW
(
szwBuffer
) *
sizeof
(
WCHAR

));

file
.
Close
();

//
以上这段代码在
unicode
和非
unicode
环境下都有效。
这里显式的指明用
Unicode
来进行操作。

2.

在非
unicode
环境下,缺省调用的都是
ANSI

式的字符串,此时
TCHAR
转换为
CHAR
类型的,除非显式定义
WCHAR
。所以在这个环境下,如果读取
unicode
文件,那么首先需要移动
2
个字节,然后读取得字符串需要用
MultiByteToWideChar
来转换,转换后字符串信息才代表
unicode
数据。

3.


unicode
环境下,缺省调用得都是
unicode
格式得字符串,也就是宽字符,此时
TCHAR
转换为
WCHAR
,相关得
API
函数也都调用宽字符类型
的函数。此时读取
unicode
文件也和上面一样,但是读取得数据是
WCHAR
的,如果要转换成
ANSI

式,需要调用
WideCharToMultiByte
。如果读取
ANSI
的,则不用移动两个
字节,直接读取然后视需要转换即可。

某些语言(如韩语)必须在
unicode
环境下才能显示,这种情况下,
在非
unicode
环境下开发,就算用字符串函数转换也不能达到显示文字的目的,因为此时调用得
API
函数是用
ANSI
的(虽然底层都是用
UNICODE
处理但是处理结果是按照程序员调用的
API
来显示的)。所以必须用
unicode
来开发。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: