现代Windows操作系统有不同的语言版本,可以支持所有国家的现有语言。这就涉及到不同字符集的编码规则。
本节需要学习的知识点:
字符集
C语言字符
宽字符和窗口
1.4.1 字符集
ASCII码半角字符集
现代计算机诞生于美国,计算机支持的第一种语言当然是美式英语。为了能够显示美式英语字符,美国人发明了ASCII码编码规则。 ASCII码使用7位二进制数来定义符号,取值范围为0到127,对应128个字符。如图1-6所示。
ASCII码有特定的书写规则,是一种非常可靠的代码,广泛应用于计算机键盘、显示器、系统硬件、打印机、字体文件、操作系统和互联网。
ASCII码只能满足美国的需要,而不能满足世界其他国家的文字符号。为了满足欧洲国家的需求,IBM创建了扩展的ASCII码表,使用8位二进制数来表示字符,最多支持256个字符。
为了统一标准,美国国家标准协会(ANSI)制定了统一标准ASCII码。这称为单字节字符集。
将计算机应用到中文、韩语、日语等东亚语言,需要编程多达数万个字符。因此,即使是8位二进制数也是不可能的。正因为如此,二进制数扩展为16位,最多允许写入216个字符,基本上满足了你的需求。
Unicode宽字节字符集
Unicode字符集为16位,最多可支持65536个字符。 Unicode 字符串中的所有字符都是16 位(2 个字节)。这样,世界上书面文本中的每个字符都可以被编码,远远超出了单字节字符集的256 个字符。然而,Unicode 并不完美。 Unicode 字符串消耗的内存是ASCII 字符串的两倍。
这65536个字符可以分为不同的区域。表1-1 显示了其中一些区域以及分配给它们的字母。
16位代码
特点
16位代码
特点
0000-007F
ASCII码
0300-036F
通用识别标记
0080-00FF
拉丁字母
0400-04FF
西里尔字母
0100-017F
欧洲拉丁语
0530-058F
亚美尼亚语
0180-01FF
扩展拉丁语
0590-05FF
希伯来语
0250-02AF
标准拼音
0600-06FF
阿拉伯
02B0-02FF
修改字符
0900-097F
梵文
2E80-2EFF
中文、日文和韩文字符的辅助部首
31C0-31EF
中文、日文、韩文笔画
表1-1 区域字符
目前,大约有29,000 个代码点未分配,但保留供将来使用。此外,大约有6,000 个代码点保留供个人使用。
字符代码UTF-8
Unicode是所有字符的统一编码,字符集只给每个字符一个唯一的编号,并没有规定编号为65的字符如何存储。然而,存储数字为40657的字符需要2个字节的空间,而后面的字符可能需要3甚至4个字节的空间。
这时候,知道用什么规则来存储Unicode字符就很重要了。为了覆盖现有Unicode 中的所有字符,您可以指定将字符存储在4 个字节(即32 位)中。 UTF -32(UTF 代表UCS 转换格式)。尽管UTF-32的规则很简单,但也有明显的缺点。仅使用使用UTF-32 和ASCII 的罗马字符需要的空间是后者的四倍(仅对于每个ASCII 字符)。必须保存1 个字节)。
对于存储和网络传输,通常使用更节省空间的变长编码UTF-8,表示使用1到4个字节来表示字符的8位组的格式。
UTF-8的编码规则如下(U+后面的数字代表Unicode字符编码):
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
正如您所看到的,UTF-8 根据前导标志位的数量实现可变长度。单字节字符只占用一个字节,因此可以包含Unicode中的所有字符,类似于UTF-32,有效减少存储和传输时占用的空间。
当前的Windows 操作系统默认使用Unicode 字符集。
1.4.2 C语言宽字符
由于本书使用C语言实现Windows程序,因此有必要介绍C语言的宽字符集函数。我们刚学C语言的时候用的是ANSI C(美国国家标准编程语言——C),它支持7位ASCII码字符。 ANSI C 还支持中文、日文和韩文版本的Windows 支持的多字节字符集。但是,这些多字节字符集被视为单字节值的字符串。多字节字符集主要影响C 语言运行时函数。相反,宽字符比常规字符更宽,这可能会导致编译问题。
宽字符不一定必须是Unicode。 Unicode 是一种可能的宽字符集。然而,由于本书的重点是Windows而不是抽象的C语言实现,因此本书可以互换使用宽字符和Unicode。
ANSI字符集char数据类型
字符c='A';
变量c需要1个字节来存储表示ASCII字符A的十六进制值0x41。
定义另一个字符串指针。
字符*p;
由于Windows是32位系统,指针变量P需要4个字节的存储空间。
char *p='你好!';
存储字符串需要7个字节的空间,其中之一是字符串末尾的NULL字符。
您还可以定义字符数组。
字符a[10];
编译器为此数组保留10 个字节的空间。 sizeof(a) 表达式返回10。
你也可以写:
char a[]='Hello!';//初始化数组
宽字符集char数据类型
使用Unicode 宽字符不会更改C 语言中的字符数据类型。 char类型仍然代表1个字节的存储,sizeof(char)返回1。理论上,C 中的一个字节可能比8 位长,但对于大多数人来说,一个字节是8 位宽。
C 语言中的宽字符基于wchar_t 数据类型。该数据类型在多个头文件中定义,包括WCHAR.H。
我使用了短typedef wchar_t。
wchar_t 数据类型为16 位宽,类似于无符号短整型。
您可以使用以下语句定义包含单个宽字符的变量:
wchar_t c='A';
变量C 的双字节值是0X0041,它是Unicode 字符A。
当Intel处理器存储多字节值时,它们总是首先存储最低有效字节(小端存储模式),因此这些字节实际上以0x41、0x00的顺序存储在内存中。在检查Unicode 文本的内存存储时,请务必牢记这一点。
wchar_t *p=L'你好!';
大写的L 代表一个长整数,后跟一个左引号。这向编译器表明该字符串是使用宽字符存储的,即每个字符使用2 个字节。指针变量p需要4个字节的存储空间,但是这个字符串需要14个字节的存储空间。
wchar_t a[]=L'你好!';
sizeof(a) 也返回14。
这可能看起来像是一个拼写错误,但引号前的L 非常重要,两个字符之间不应有空格。只有有了这个L,编译器才知道必须使用两个字节来存储字符串中的一个字符。
wchar_t c=L'A';
对于单个字符,可以使用L 前缀来表示宽字符,或者保留默认值,编译器会自动添加0。
C语言标志库函数支持ANSI和宽字符集函数。有关详细信息,请参阅下一节中的表1-2。
1.4.3 Windows宽字符
ANSI 和UNICODE 函数的兼容性
Windows 提供了ANSI 和UNICODE 字符串操作的函数,以及一组与两者兼容的函数。例如:
例子
示例1:
#ifdef 统一码
#define _tcscpy wcscpy
其他的
#define _tcscpy strcpy
#endif
示例2:
#ifdef 统一码
#define 消息框消息框W
其他的
#define 消息框消息框A
#endif //!UNICODE
尖端
1、Windows API函数定义了Unicode函数和相应的ASCII函数,将ASCII字符转换为Unicode字符,并由Unicode函数实现。
2、Windows操作系统中的动态链接库函数名和动态链接库名都是ASCII字符。
Windows头文件的类型
WINDOWS.H 头文件包含许多其他头文件,包括:
WINDEF.H头文件:基本数据类型定义
WINNT.H头文件:负责处理基本的Unicode支持函数。
WINNT.H头文件的开头是一个C头文件CTYPE.H,它定义了wchar_t数据类型。 WINNT.H 头文件定义了两种新的数据类型:CHAR 和WCHAR。
typedef 字符CHAR;
typedef char WCHAR;
CHAR 和WCHAR 是Windows 推荐的数据类型,分别定义8 位和16 位字符。 WCHAR wc 之后的注释建议使用匈牙利表示法来指示这是基于WCHAR 数据类型的变量,即宽字符。
然后,WINNT.H 头文件定义了六种可用作8 位字符串指针的数据类型和四种可用作const 8 位字符串指针的数据类型。
typedef CHAR *PCHAR、*LPCH、*PCH、*NPSTR、*LPSTR、*PSTR;
typedef CONST CHAR *LPCCH、*PCCH、*LPCSTR、*PCSTR;
前缀N 和L 代表近和长,指的是16 位Windows 系统上两个不同大小的指针。但在win32 上,near 和long 指针没有区别。
同样,下面的WINNT.H头文件定义了六种可用作16位字符串指针的数据类型和四种可用作const 16位字符串指针的数据类型。
typedef WCHAR *PWCHAR、*LPWCH、*PWCH、*NWPSTR、*LPWSTR、*PWSTR;
typedef CONST WCHAR * LPCWCH,* PCWCH,* LPCWSTR,* PCWSTR;
通过这种方式,您可以获得指向CHAR 和WCHAR 数据类型的不同指针。与TCHAR.H 一样,WINNT.H 将TCHAR 定义为通用字符类型。如果定义了标识符_UNICODE,则指向TCHAR 的指针将定义为WCHAR,而TCAHR 将定义为指向WCHAR 的指针。如果未定义标识符UNICODE,则TCHAR 被定义为char 或指向char 的指针。
#ifdef 统一码
typedef WCHAR TCHAR, *PTCHAR;
typedef LPWSTR LPTCH、PTCH、PTSTR、LPTSTR;
typedef LPCWSTR LPCTSTR;
其他的
typedef char TCHAR, *PTCHAR;
typedef LPSTR LPTCH、PTCH、PTSTR、LPTSTR;
typedef LPCSTR LPCTSTR ;
#endif
当在头文件中定义TCHAR 时,WINNT.H 和WCHAR.H 头文件都会防止重复定义TCHAR 数据类型。 WINNT.H 头文件还定义了一个宏,该宏将L 添加到字符串的第一个引号中。
#define __TEXT(quote) L##quote //UNICODE 已定义
#define __TEXT(quote) quote //UNICODE未定义
无论如何,TEXT宏定义如下:
#define __TEXT(引用) __TEXT(引用)
这些定义允许您在同一程序中混合ASCII 和Unicode 字符串。
Windows NT 从一开始就支持Unicode。这意味着Windows NT 在内部使用16 位字符串。由于世界上许多地方尚未使用16 位字符串,因此Windows NT 操作系统必须频繁地在内部转换字符串。 Windows NT 可以运行专门为ASCII 和UNICODE 编写的程序,或者为ASCII 和Unicode 混合编写的程序。实际上是通过相关的API函数来实现的。
Windows 字符串函数
Microsoft C 包括需要字符串参数的C 语言运行时函数的宽字符和通用版本。然而,Windows 复制了其中一些C 函数。
ILength=lstrlen(pString);
pString=lstrcpy(pString1, pString2);
pString=lstrcpyn(pString1, pString2, iCount);
pString=lstrcat(pString1, pString2);
iComp=lstrcmp(pString1, pString2);
iComp=lstrcmpi(pString1, pString2);
这些函数提供与C 运行时库中的函数等效的函数。如果定义了UNICODE 标识符,这些函数支持宽字符串。否则,仅接受常规字符串。
如何在Windows上使用printf
不幸的是,Windows没有标准输入和标准输出的概念,因此不能在Windows程序中使用printf函数。然而,fprintf 和sprintf 函数可以在Windows 程序中使用。
函数原型:
int printf (const char * szFormat,);
int sprintf (char * szBuffer, const char * szFormat,);
sprintf 函数不会将格式化结果写入标准输出,而是将它们存储在szBuffer 缓冲区中。
printf('%i 和%i 之和为%i', 5, 3, 5+3);
功能上相当于:
char szBuffer[100];
sprintf(szBuffer, '%i 和%i 之和为%i', 5, 3, 5+3);
put(szBuffer);
【注意】缓冲区必须足够大。
sprintf 函数还有一个变体函数,即vsprintf 函数。
int sprintf (char * szBuffer, const char * szFormat,)
{
int iReturn;
va_list pArgs;
va_start(pArgs, szFormat);
iReturn=vsprintf(szBuffer, szFormat, pArgs);
va_end(pArgs);
返回iReturn。
}
指C语言变量参数的内容。
由于许多早期的Windows 程序都使用sprintf 和vsprintf 函数,因此Windows API 中添加了两个类似的函数:wsprint 和wvsprintf。
随着宽字符的引入,添加了许多sprintf 函数,如下表所示。
ASCII码
宽字符
普遍的
可变数量的参数
普通版
短跑
swprintf
_stprintf
最大长度版本
_sprintf
_snwprintf
_sntprintf
Windows版本
wsprintf
wsprintfW
wsprintf
指向参数数组的指针
普通版
VSprintf
打印输出
_vstprintf
最大长度版本
_vsnprintf
_vsnwprintf
_vsntprintf
Windows版本
wvsprintfA
wvsprintfW
wvsprintf
表1-2 printf函数
在sprintf 函数的宽字符版本中,字符串缓冲区被定义为宽字符串。该函数的所有宽字符版本都要求格式字符串是宽字符字符串。但是,您有责任确保传递给这些函数的其他字符串也是宽字符串。
常用字符串处理函数对照表
美国国家标准协会
统一码
普遍的
解释
数据类型
(字符.h)
(wchar.h)
(tchar.h)
特点
wchar_t
查尔
特点*
wchar_t*
查尔*
LPSTR
LPWSTR
LPTSTR
线性PCSTR
LPCWSTR
LPCTSTR
字符串转换
阿托伊
_wtoi
_土井
将字符串转换为整数(int)
阿瑟尔
_wtol
_ttol
将字符串转换为长整型。
阿托夫
_wtof
_tstof
将字符串转换为浮点数(双精度)。
伊托亚
_itow
_伊托
将任何类型的数字转换为字符串
字符串操作
斯特伦
惠斯伦
_tcslen
获取字符串数量
结构体
wcscpy
_tcscpy
复制字符串
结构体
wcsncpy
_tcsncpy
与strcpy/wcscpy类似,但指定副本数。
STRCMP
西西康普
_tcscmp
比较两个字符串
STRNCMP
西西尼康普
_tcsncmp
与strcmp/wcscmp 类似,但指定要比较的字符串数量。
斯特拉卡特
世界猫
_tcscat
将一个字符串附加到另一个字符串的末尾
字符串猫
网络猫
_tcsnccat
与strcat/wcscat 类似,但指定粘合字符串的粘合长度。
拉紧
西西
_tcshr
查找子串的第一个位置
延长
WCSRCR
_tcsrchr
查找子字符串末尾的第一个匹配项。
斯特普布克
西斯普布鲁克
_tcspbrk
查找一个字符串中的任何字符在另一个字符串中第一次出现的位置。
斯特斯特
wcsstr/wcswcs
_tcsstr
查找字符串中另一个字符串的第一次出现
字符串
西西斯普恩
_tcscspn
返回不包含第二个字符串的第一个数字。
字符串
华西斯普恩
_tcsspn
返回包含第二个字符串的第一个数字。
斯特拉谈话
灯芯库存
_tcstok
根据标识符将字符串拆分为一系列字符串。
西坐标宽度
获取宽字符串的宽度
厕所宽度
获取宽字符宽度
字符串测试
伊萨斯基
伊斯瓦西人
_istacii
测试字符是否为ASCII 字符。即判断c是否在0~127范围内。
伊萨努姆
伊斯瓦南
_istalnum
测试一个字符是数字还是字母
阿尔法
伊斯瓦尔法
_伊斯塔法
测试一个字符是否是一个字符
iscntrl
是wcntrl
_istcntrl
测试一个字符是否是控制字符
这是一个数字
这是一个数字
_istdigit
测试一个字符是否是数字
伊斯格拉夫
冰图
_istgraph
测试字符是否为可显示字符
低的
爱笑的人
_伊斯特鲁
测试字符是否为小写
印刷
打印
_istprint
测试字符是否可打印
被打断
我有一只轮胎瘪了
_istpunct
测试一个字符是否是标点符号
空间
空间空间
_istspace
测试字符是否为空白字符
上面是
伊斯瓦珀
_istupper
测试字符是否为大写
是x数字
是wx数字
_istxdigital
测试字符是否为十六进制数字
大小写转换
底部
塔塔
_ 及以下
将字母转换为小写
塔珀
脚趾上部
_totupper
将字母转换为大写
人物比较
斯特拉科莱
瓦斯科科尔
_tcscoll
比较字符串
日期和时间转换
填充时间
时间
_tcsftime
根据指定的字符串格式和区域设置设置日期和时间的格式
时间
根据指定格式将字符串转换为时间值。这是strftime的逆过程。
打印和扫描字符串
打印
打印函数
_tprintf
使用可变长度参数格式化输出到标准输出
打印函数
打印输出
_ftprintf
具有可变参数的格式化输出
扫描仪
扫描仪
_tscanf
从标准输入格式化读取
扫描仪
扫描仪
_ftscanf
格式化读取
短跑
swprintf
_stprintf
根据vararg参数表将其格式化为字符串。
扫描仪
扫描仪
_stscanf
读取格式化字符串
打印函数
打印输出
_vftprintf
使用stdarg 参数表将输出格式化为文件
打印函数
使用stdarg 参数表将输出格式化为标准输出
VSprintf
打印输出
_vstprintf
格式化stdarg 参数表并写入字符串
sprintf_s
swprintf_s
_stprintf_s
格式字符串
数字化转型
支撑
沃斯托德
_tcstod
将字符串的第一部分转换为双精度浮点数。
斯特拉特尔
维克斯塔尔
_tcstol
将字符串的第一部分转换为长整数
斯特拉图尔
惠斯托尔
_tcstoul
将字符串的第一部分转换为无符号长整数。
_strtoi64
_wcstoi64
_tcstoi64
输入/输出
弗吉特
fgetwc
_fgettc
从流中读取字符并将其转换为宽字符
弗格茨
弗吉特斯
_fgetts
从流中读取字符串并将其转换为宽字符串。
弗普特克
fputwc
_fputtc
将宽字符转换为多字节字符并输出到标准输出
输出量
弗普特斯
_fputts
将宽字符串转换为多字节字符并将其打印到标准输出字符串。
得到
上厕所
_gettc
从标准输入读取字符并将其转换为宽字符。
明白了
获得
_getchar
从标准输入读取字符
普奇
放厕所
_puttc
标准输出
投手
普查尔
_puttchar
标准输出
ETC。
无法获得
_ungettc
返回字符到输入流
表1-3 常用字符串处理函数对比表
版权声明:本文转载于网络,版权归作者所有。如有侵权,请联系本站编辑删除。