windows程序设计(六)Unicode码与ASCII码

ASCII码

ASCII码(ASCII:American Standard Code for Information Interchange)被叫做 美国信息交换标准代码,标准ASCII是由七位的二进制数来表示,一共可以表示2^7=128个标准字元码,其中包含就有 26 个小写字母、26 个大写字母、10 个数字、32 个符号、 33 个代号和一个空格。
标准ASCII码有很多优点:26个字母是连续的,大写小写字母可以通过改变一位来进行相互转化,并且它非常可靠。但是由于很多符号还没有,例如英镑的符号£,因此,标准ASCII的表示还并不足够。
之后又改进形成了八位二进制数来表示的扩展ASCII码,一共可以表示2^8=256个字元码。

DBCS码

DBCS码(DBCS::double-byte character set)又叫做双位元组字元集 ,它使用两个七位的二进制来表示象形文字,这两个位的元分别被叫做首位元组和跟随为元组。这两个元组一起定义一个字元,通常是一个复杂的象形文字。
但是有的文字,只需要用一位元组来进行表示,这会引起附加程序设计的问题。

Unicode

Unicode 是统一的 16 位二进制数来表示,这样就允许表示 2^16=65,536 个字元。这对于世界上所有的字元以及象形文字语言都是充裕的。
Unicode使用的是宽字元集,即Unicode中的每个字元都是16位宽而不是8位宽,与DBCS码不同的是,Unicode中所有的字符都用到16位,处理起来非常方便。
在Unicode码中前128字元位标准ASCII码的字元(0x0000到0x007F),接下来的128个字元是扩展ASCII码中扩展的128个字元(0x0080到0x00FF),希腊字母表使用 0x0370 到 0x03FF 的码元,中国日本韩国的象形文字(总成CJK)使用了从
0x3000 到 0x9FFF 的码元。
Unicode 的最大好处是这里只有一个字元集。

char类型

char类型可以用来存储单个字符,char类型的数组可以储存字符串类型。

char c = 'A';

对于该语句,变量c需要1个字节即8位二进制数来在计算机中存储,大写字母A存储的0x41,A在ASCII码表中也是这么表示的。
我们也可以通过定义char类型的指针来指向单个字符,只不过单个字符在计算机中的存储并不会发生改变。

char a[10]

对于char类型的数组,在上述情况下,编译器向系统申请保留了10个子节用来存储char类型的字符串。

char *p = "hello"

在上述情况下,变量p位char类型的指针需要4个子节来存储,指向后面字符串的第一个字符。对于后面的字符串,它在系统所占大小为6个字节,最后一个字节保存的是字符串终止记号\0。

宽字符

在C中,宽字符是使用wchar_t类型表示的,该类型是实现定义的宽字符类型。 在 Microsoft 编译器,它表示用来存储 Unicode 编码为 UTF 16LE 的 16 位宽字符在 Windows 操作系统上的本机字符类型。

wchar_t c = 'A';

对于上面的这种情况,变量c申请2个子节来存放字符A,此时字符A用16位2进制数来表示,即0x0041,这是Unicode对大写字母A的表示。

wchar_t *p = L"Hello"

对于上面的这种情况,定义了一个wchar_t类型的指针指向后面的字符串,在第一个引号之前的大写L字母表示long。这样的话,编译器在编译时,就会将这个字符串按照宽字符类型来存储。这个字符串总共需要12字节来保存,每个子节16位二进制数来表示,结尾的结束符也要占两个字节。

wchar_t c = L'A' ;

还可以通过上面的方法用在单个字符上,但这并不是必要的,编译器会自动对字符进行扩充。

宽字符相关函数

#include <stdio.h>
#include <string.h>
int main(void) {
	wchar_t *p = L"hello";
	printf("%d", strlen(p));
	return 0;
}

对于以上代码的编译是不能成功的,在strlen函数会抛出错误,即wchar_t 类型与contest char类型不相符合的。在处理宽字符字符串时,必须使用特定的宽字符函数。
要查看宽字符字符串的长度需要使用wcslen(wide-character string length:宽字 串长度),它时strlen的宽字元版。

#include <stdio.h>
#include <string.h>

int main(void) {
	wchar_t *p = L"hello";
	printf("%d", wcslen(p)); //5
	return 0;
}

改成宽字符时,字符串的字符长度不变,只是每一个字符都变成了16位二进制数存储。
对于MessageBox函数在用法上也有一些区别,MessageBox函数的定义如下

int WINAPI MessageBox (HWND, LPCSTR, LPCSTR, UINT) ; 

可以看到,对于该函数,其第二个和第三个参数都是指向字符串的指针。在 USER32.DLL 中,没有 32 位元 MessageBox 函式的进入点。实际上,有 两 个进入点,一个名为 MessageBoxA(ASCII 版),另一个名为 MessageBoxW(宽字元版)。
MessageBoxA函数的定义如下所示:

WINUSERAPI int WINAPI MessageBoxA ( HWND hWnd, LPCSTR lpText,     
										LPCSTR lpCaption, UINT uType) ; 

MessageBoxW函数的定义如下所示:

WINUSERAPI int WINAPI MessageBoxW (HWND hWnd, LPCWSTR lpText,     
										LPCWSTR lpCaption, UINT uType) ;

可以看到在MessageBoxW中的第二个和第三个参数,都是指向宽字节的指针。
在编译的过程中,可以判断所要编译的字符类型是否为Unicode来进行预编译。

#ifdef UNICODE 
#define MessageBox  MessageBoxW 
#else
#define MessageBox  MessageBoxA 
#endif 

下面是windows中用来处理比较宽字节字符串的常用函数:

ILength = lstrlen (pString) ;//返回字符串长度
pString = lstrcpy (pString1, pString2) ; //将字符串复制到缓冲区已经使用
pString = lstrcpyn (pString1, pString2, iCount) ; //将指定数量字符串中的字符复制到缓冲区
pString = lstrcat (pString1, pString2) ; //将一个字符串附加到另一个字符串后
iComp = lstrcmp (pString1, pString2) ; //比较两个字符串
iComp = lstrcmpi (pString1, pString2) ;//比较两个字符串

lstrcpy 函数的做作用是将pString2所指向的字符串赋值给pString1所指向的缓冲区。目前已经使用StringCchCopy函数来替代。
lstrcpyn 函数与lstrcpy函数类似,只不过置定要的传送几位数字,目前已经被StringCchCopy函数替代。
lstrcat 函数是将两个字符串附加,即将pString2指向的字符串附加到pString1指向的字符串之后。目前该函数已被StringCchCat函数替代。
lstrcmp函数用来比较两个字符串,区分大小写。若pString1字符串大于pString2字符串返回正数,若pString1字符串小于pString2字符串返回负数,相等则返回0。
lstrcmpi 函数用来比较两个字符串,但不区分大小写,用法类似与lstrcmp函数。

在Windows中使用printf

printf函数是我们最常见的可以在控制台输出字符的函数,但是在很多场合下,是不能用printf函数进行输出文字的功能的。可以使用fprintf或者sprintf等函数来进行字符的显示。
对于print函数来说,它的具体细节如下所示:

int printf (const char * szFormat, ...) ;

第一个参数是格式字符串,后面的一些参数则是控制该字符串屏幕上的显示。
在使用的时候可以按照下面语句进行使用:

printf ("The sum of %i and %i is %i", 5, 3, 5+3) ; 

sprintf函数的定义如下所示:

int sprintf (char * szBuffer, const char * szFormat, ...) ; 

第一个参数是字符串缓冲区,第二个参数指向的是一个格式字符串。sprintf函数不会将字符串输出,而是把字符串存入缓冲区中,返回该字符串的长度。对于上面printf的使用换成sprintf函数如下:

char szBuffer [100] ; 
sprintf (szBuffer, "The sum of %i and %i is %i", 5, 3, 5+3) ; 
puts (szBuffer) ;

要注意在使用sprintf函数时,必须满足缓冲区足够大。

参考资料:
[1]《Windows程序设计(第五版)》
[2]https://docs.microsoft.com/zh-cn/welcome-to-docs

发布了20 篇原创文章 · 获赞 0 · 访问量 756

猜你喜欢

转载自blog.csdn.net/LeavingBook/article/details/104262929