Windows核心编程第二章,字符串的表示以及宽窄字符的转换

时间:2021-12-25 03:46:42

Windows核心编程,字符串的表示以及宽窄字符的转换

1.字符集

1.1.双字节字符集DBCS

何为双字节字符集,在以前我们都是将文本字符串编码为一组以0结尾的单字符.

可以调用strlen进行判断结尾是否是0进而返回字符串的字符个数.

双字节字符集都是由1个或者2个字节组成.日本的汉子就是字符在0x81到0x9f

之间.或者在0xE0 - 0XFC之间,需要检查下一个字节才能判断是一个完整汉字

对于我们来说,一会1个字节,一会两个字节很麻烦,所以除了UNICODE字符集.

1.2 Unicode字符集

Unicode是一项标准,实在1988年由Apple和Xerox建立的.1991是专门成立协会来开发跟推动Unicode标准的.

Unicode每个字符都是使用了UTF-16的编码,Unicode全称(Unicode Transformation Format)(Unicode转换格式) UTF-16编码是将每个字符编码为2个字节.或者是16位.

注意: Unicode是标准. 而 UTF-16才是编码. 注意两者的区别.

1.3 UTF-8编码

除了上边所说的 UTF-16的编码.其实我们也有其余的UTF标准,如UTF - 8

UTF-8是将一些字符编码为1个字节,一些字符编码为两个字节.一些字符编码为3个字节或者4个字节.

了解:

值在0x0080以下的字符,会压缩为1个字节.这符合美国的标准.

值在0x0080 - 0x7FF之间,字符会转换为2个字节.这对欧洲以及东欧非常适合.

值在0x0800以上的字符,都会是3个字节,适合东亚地区的语言

最后代理对被谢伟4个字节, UTF-8是一种相当流向的编码格式.但值在0x800以上,翻译为3个字节的时候,不如UTF-16编码实用.高效.

1.4 UTF - 32编码.

UTF-32编码就是对每一个字节都编程4个字节存储.

如果打算写一个算法,处理字节数不定的字符.就可以实用这种编码.

这种编码用的少.一般都用于应用程序内部,很少用于网络.

1.5 Unicode标准包含的对照表.

2.Ansi字符与Unicode字符的字符串数据类型

2.1.Ansi 与 Unicode数据类型

ANSI:

在C语言中,char是我们常用的数据类型,这个数据类型表示了一个8位的ANSI字符.

如果源代码中,我们声明一个字符串,那么如果是C编译器,则会把字符串中的字符转换为

Char(8位)数据类型构成的一个数组.

如下:

Char c = ‘A’
Char szBuff[] = “ABC”

SzBuff是一个数组,其中 数组的每一项都是一个字符.

UNICODE:

在VC++中,编译器定义了一个自己建立的数据类型. wchar_t,他表示一个16位的Unicode标准的字符. 早期是没有定义的,我们需要在编译器中增加选项 /Zc:wchar_t 才会定义这个数据类型.

如VC++6.0就是需要指定,或者加宏.

UNICODE标准的字符表示方法

Wchar_t  c = L’A’;  宽字符定义的时候需要加L表示这是个宽字符
Wchar_t wzBuf[] = L”ABC”;定义字符串.

2.2添加的新的数据类型

为了便于程序的编写,windows在WinNt.h中定义了许多新的类型

如下:

typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
#else
// some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
#endif typedef WCHAR *PWCHAR, *LPWCH, *PWCH;
typedef CONST WCHAR *LPCWCH, *PCWCH; typedef _Null_terminated_ WCHAR *NWPSTR, *LPWSTR, *PWSTR;
typedef _Null_terminated_ PWSTR *PZPWSTR;
typedef _Null_terminated_ CONST PWSTR *PCZPWSTR;
typedef _Null_terminated_ WCHAR UNALIGNED *LPUWSTR, *PUWSTR;
typedef _Null_terminated_ CONST WCHAR *LPCWSTR, *PCWSTR;
typedef _Null_terminated_ PCWSTR *PZPCWSTR;
typedef _Null_terminated_ CONST PCWSTR *PCZPCWSTR;
typedef _Null_terminated_ CONST WCHAR UNALIGNED *LPCUWSTR, *PCUWSTR; typedef _NullNull_terminated_ WCHAR *PZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR *PCZZWSTR;
typedef _NullNull_terminated_ WCHAR UNALIGNED *PUZZWSTR;
typedef _NullNull_terminated_ CONST WCHAR UNALIGNED *PCUZZWSTR; typedef WCHAR *PNZWCH;
typedef CONST WCHAR *PCNZWCH;
typedef WCHAR UNALIGNED *PUNZWCH;
typedef CONST WCHAR UNALIGNED *PCUNZWCH; #if _WIN32_WINNT >= 0x0600 || (defined(__cplusplus) && defined(WINDOWS_ENABLE_CPLUSPLUS)) typedef CONST WCHAR *LPCWCHAR, *PCWCHAR;
typedef CONST WCHAR UNALIGNED *LPCUWCHAR, *PCUWCHAR; _NullNull_terminated 宏的含义
宏是一个头部注解,藐视了一些类型.如何用作函数的参数以及返回值.
我们可以设置代码分析(Code Analysis) 把/analyze开关添加到编译器的命令行中.这样调用函数的话.编译器则会进行检测了.

2.3 TEXT()宏的使用

在Windows中,定义了TEXT()宏,作用就是,我们上面的内建数据类型.有ANSI数据类型,也有UNICODE类型.为了自动使用数据类型,根据编译器当前选择的字符集选项.自动使用数据类型.

如下:

#ifdef  UNICODE                     // 编译器使用ifdef语句自动判断你是否使用的是UNICODE字符集,如果是则下面生效.

#ifndef _TCHAR_DEFINED
typedef WCHAR TCHAR, *PTCHAR;
typedef WCHAR TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */ typedef LPWCH LPTCH, PTCH;
typedef LPCWCH LPCTCH, PCTCH;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR PCTSTR, LPCTSTR;
typedef LPUWSTR PUTSTR, LPUTSTR;
typedef LPCUWSTR PCUTSTR, LPCUTSTR;
typedef LPWSTR LP;
typedef PZZWSTR PZZTSTR;
typedef PCZZWSTR PCZZTSTR;
typedef PUZZWSTR PUZZTSTR;
typedef PCUZZWSTR PCUZZTSTR;
typedef PZPWSTR PZPTSTR;
typedef PNZWCH PNZTCH;
typedef PCNZWCH PCNZTCH;
typedef PUNZWCH PUNZTCH;
typedef PCUNZWCH PCUNZTCH;
#define __TEXT(quote) L##quote // r_winnt #else /* UNICODE */ // r_winnt #ifndef _TCHAR_DEFINED
typedef char TCHAR, *PTCHAR;
typedef unsigned char TBYTE , *PTBYTE ;
#define _TCHAR_DEFINED
#endif /* !_TCHAR_DEFINED */ typedef LPCH LPTCH, PTCH;
typedef LPCCH LPCTCH, PCTCH;
typedef LPSTR PTSTR, LPTSTR, PUTSTR, LPUTSTR;
typedef LPCSTR PCTSTR, LPCTSTR, PCUTSTR, LPCUTSTR;
typedef PZZSTR PZZTSTR, PUZZTSTR;
typedef PCZZSTR PCZZTSTR, PCUZZTSTR;
typedef PZPSTR PZPTSTR;
typedef PNZCH PNZTCH, PUNZTCH;
typedef PCNZCH PCNZTCH, PCUNZTCH;
#define __TEXT(quote) quote // r_winnt #endif /* UNICODE */ // r_winnt
#define TEXT(quote) __TEXT(quote) // r_winnt typedef SHORT *PSHORT;
typedef LONG *PLONG;

3.Windows中的Unicode与Ansi函数

在Windows中,API(应用程序接口) 是分为A版本,与W版,经常听别人怎么说.

其实意思就是你使用的函数兼容Ansi字符的还是兼容Unicode标准的.

在Windows NT版本以后,所有的版本都是用Unicode组建的,核心都是Unicode组建的.

也就是说你调用A版函数.底层会转换参数,供W版使用.

如我们常见的函数:

MessageBoxA MessageBoxW LoadLibraryA LoadLibraryW

有时候我们调用的是Windows的宏, 如 我们直接调用 MessageBox. 其实它是一个宏,跟Text()宏一样,判断你当前的编译器环境,如果是Unicode环境,那么他就会调用 MessageBoxW.

3.1 对于Com接口的移植

Windows逐渐提供W版本函数但是也会有A函数.这种是不能替代的.

而Com组件从16位移植到32位的时候.都是使用的Unicode字符串作为参数了.

因为Com接口适用于让不同的组建进行对话.而Unicode是最好的选择.

4.C 运行库中的Unicode跟Ansi函数

4.1.C运行库中的函数

C运行库中的函数不存在 A W版本.你调用的A就是A,你调用的W就是W

如我们常见的字符串函数 strcmp 与 wcscmp. 必须使用不同的函数才可以.

而这些函数.在Tchar.h中.定义了宏.

#define _tcscat         wcscat
#define _tcscat_s wcscat_s
#define _tcschr wcschr
#define _tcscpy wcscpy
#define _tcscpy_s wcscpy_s
#define _tcscspn wcscspn
#define _tcslen wcslen
#define _tcsnlen wcsnlen
#define _tcsncat wcsncat
#define _tcsncat_s wcsncat_s
#define _tcsncat_l _wcsncat_l
#define _tcsncat_s_l _wcsncat_s_l
#define _tcsncpy wcsncpy
#define _tcsncpy_s wcsncpy_s
#define _tcsncpy_l _wcsncpy_l
#define _tcsncpy_s_l _wcsncpy_s_l
#define _tcspbrk wcspbrk
#define _tcsrchr wcsrchr
#define _tcsspn wcsspn
#define _tcsstr wcsstr
#define _tcstok _wcstok
#define _tcstok_s wcstok_s
#define _tcstok_l _wcstok_l
#define _tcstok_s_l _wcstok_s_l
#define _tcserror _wcserror
#define _tcserror_s _wcserror_s
#define __tcserror __wcserror
#define __tcserror_s __wcserror_s #define _tcsdup _wcsdup
#define _tcsnset _wcsnset
#define _tcsnset_s _wcsnset_s
#define _tcsnset_l _wcsnset_l
#define _tcsnset_s_l _wcsnset_s_l
#define _tcsrev _wcsrev
#define _tcsset _wcsset
#define _tcsset_s _wcsset_s
#define _tcsset_l _wcsset_l
#define _tcsset_s_l _wcsset_s_l #define _tcscmp wcscmp
#define _tcsicmp _wcsicmp
#define _tcsicmp_l _wcsicmp_l
#define _tcsnccmp wcsncmp
#define _tcsncmp wcsncmp
#define _tcsncicmp _wcsnicmp
#define _tcsncicmp_l _wcsnicmp_l
#define _tcsnicmp _wcsnicmp
#define _tcsnicmp_l _wcsnicmp_l #define _tcscoll wcscoll
#define _tcscoll_l _wcscoll_l
#define _tcsicoll _wcsicoll
#define _tcsicoll_l _wcsicoll_l
#define _tcsnccoll _wcsncoll
#define _tcsnccoll_l _wcsncoll_l
#define _tcsncoll _wcsncoll
#define _tcsncoll_l _wcsncoll_l
#define _tcsncicoll _wcsnicoll
#define _tcsncicoll_l _wcsnicoll_l
#define _tcsnicoll _wcsnicoll
#define _tcsnicoll_l _wcsnicoll_l
使用 _t开头是Windows定义的宏,作用就是,当你定义了Unicode标准的时候,就会扩展为使用Unicode标注你的C库函数.如 _tcslen ,如果是Unicode标注,则使用 wcslen,否则则使用strlen.

4.2 C库中的安全函数

在C库中定义了许多安全函数. 如 strcpy字符串拷贝与wcscpy

它们只是负责拷贝.但是并不会决定拷贝多少.以至于会破坏内存.

破坏内存则会引起 黑客的攻击. 所以现在一般都是 后面加上s



Strcpy_s 等等.可以指定长度.

5.Unicode使用技巧

5.1字符与字符串的处理方式

作用 演示

TCHAR 或者 PTSTR 来表示文本字符以及字符串

	TCHAR Buffer[] = TEXT(“”);\
PTSTR Buffer = TEXT(‘a’);

TEXT() _T()宏进行包含 作用就是根据环境自动选择字符集.

_countof()函数 求缓冲区大小,不是使用sizeof(szBuffer)了,使用_countof(szbuff);

如:

Void *p = malloc(_countof(szbuffer));

%s %S %ls格式化输出 %s输出ANSI

%ls输出宽字符

_tcslen_s()安全的函数 多使用后缀带有_s的函数.

/Gs 检测缓冲区溢出 Gs选项可以检测缓冲区溢出

Lstrcat lstrcpy 这个是Kerner32中处理字符的方法,不要使用.

CompareStringOrdinal

CompareStringEx 检测XML元素属性/注册表使用这些进行比较.不用考虑区域设置.

6.Unicde标准与Ansi之间的转换

主要是两个API

6.1.ANSI转Unicode字符的API

int MultiByteToWideChar(UINT CodePage,
DWORD dwFlags,
_In_NLS_string_(cbMultiByte)LPCCHlpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar );

参数:

Codepage:用于执行转换的代码页,跟国际有关.一般使用 CP_ACP值,作用就是使用当前系统默认的Ansi代码页.

dwFlags: 允许我们进行额外的控制.一般不使用.所以填充0.

lpMultibyteStr: 你要转换的Ansi数组

CbMultibyte: 你要转换的Ansi数组的大小

LpWideCharstr: 传入一个宽字符的空数组.转换后的字符串传出到这个数组中.

Cchwidechar: 你传入的宽字符空数组的大小.

例子:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{ char szBuffer[] = "HelloWorld";
DWORD szBufferLen = sizeof(szBuffer) / sizeof(szBuffer[0]);
TCHAR wszBuffer[100] = { 0 };
DWORD dwWszBufferLen = 100; MultiByteToWideChar(CP_ACP, 0, szBuffer, szBufferLen,(LPWSTR)&wszBuffer, dwWszBufferLen); printf("%ls \r\n", wszBuffer);
system("pause"); return 0;
}

注意传入宽字符数组的时候,传入的是它的地址.你传入地址函数内部才能根据地址将转换的ANSI转换后的值赋值给字符串数组.

6.2.UniCode转ANSI的API

int
WINAPI
WideCharToMultiByte(
_In_ UINT CodePage,
_In_ DWORD dwFlags,
_In_NLS_string_(cchWideChar) LPCWCH lpWideCharStr,
_In_ int cchWideChar,
_Out_writes_bytes_to_opt_(cbMultiByte,return) LPSTR lpMultiByteStr,
_In_ int cbMultiByte,
_In_opt_ LPCCH lpDefaultChar,
_Out_opt_ LPBOOL lpUsedDefaultChar
);

参数比ANSI转UNicode多了最后两个

LpDefaultChar:这个选项是你转换后你的字符不能正常使用.你则需要指定代码页.

使用系统默认的则使用NULL,. 要获取系统默认字符就要用GetCPinfo或者加Ex的函数.

LpUsedDefaultChar:指向该标志的指针,标志表示该函数是否在转换中使用默认字符.

如果一个字符,是无法在代码页中表示的话,我们设置为TRUE,否则就设置为FALSE或者NULL

例子:

int main()
{ TCHAR wzBuffer[] = TEXT("HelloWorld");
char szBuff[100] = { 0 };
DWORD szBufflen = 100;
DWORD dwWzBufferlen = (sizeof(wzBuffer) / sizeof(wzBuffer[0])) * 2; WideCharToMultiByte(CP_ACP, 0,wzBuffer, dwWzBufferlen, szBuff, szBufflen, 0, 0); printf("%s \r\n", szBuff);
system("pause"); return 0;
}

注意要设置Unicode字符集.如果不设置,则TCHAR相当于是char类型.所以转换就是乱码.

Windows核心编程第二章,字符串的表示以及宽窄字符的转换的更多相关文章

  1. windows核心编程---第二章 字符和字符串处理

        使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...

  2. windows核心编程-第二章 Unicode

    第2章U n i c o d e 随着M i c r o s o f t公司的Wi n d o w s操作系统在全世界日益广泛的流行,对于软件开发人员来说,将目标瞄准国际上的各个不同市场,已经成为一个 ...

  3. Windows核心编程第一章&period;错误处理

    Windows核心编程第一章,错误处理. 一丶错误处理 1.核心编程学习总结 不管是做逆向,开始做开发.在Windows下.你都需要看一下核心编程这本书.这本书确实写得很好.所以自己在学习这本书的同时 ...

  4. windows核心编程---第九章 同步设备IO与异步设备IO之同步IO

    同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...

  5. &lbrack;转&rsqb;Windows Shell 编程 第二章 【来源:http&colon;&sol;&sol;blog&period;csdn&period;net&sol;wangqiulin123456&sol;article&sol;details&sol;7987893】

    第二章Shell的结构  “Shell 编程”的大伞之下有大量的API函数和COM接口.这个种类繁多的‘命令’集允许你用不同的方法对Windows Shell进行编程.函数和接口并不是两种提供相同功能 ...

  6. Windows核心编程 第二十章 DLL的高级操作技术

    第2 0章 D L L的高级操作技术 看了下这章的内容,谈不上高级,都是些常用相关,但是还是有一些细节需要注意. 20.1 DLL模块的显式加载和符号链接 如果线程需要调用D L L模块中的函数,那么 ...

  7. windows核心编程---第一章 谈谈windows中的错误处理机制

        我们写的函数会用返回值表示程序执行的正确与否,使用void,就意味着程序一定不会出错.Bool类型标识true时为真,false时为假.其他类型根据需要可以定义成不同意义.       Win ...

  8. Windows核心编程 第九章 线程与内核对象的同步&lpar;下&rpar;

    9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...

  9. windows核心编程-第一章 对程序错误的处理

    第一章-对程序错误的处理 在开始介绍Microsoft Windows 的特性之前,必须首先了解 Wi n d o w s的各个函数是如何进行错误处理的. 当调用一个Wi n d o w s函数时,它 ...

随机推荐

  1. 日货EmEditor的使用小技巧

    1.查看->大纲向导,可层级显示HTML 2.工具->插件->资源管理器,可在左侧显示资源管理器 3.工具->插件->单词自动完成,可实现单词智能提示功能

  2. 组合模式(Composite Pattern)

    组合模式主要用来处理一类具有“容器特征”的对象——即它们在充当对象的同时,又可以作为容器包含其他多个对象. 组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口.这就是组合模式能够将组 ...

  3. webkit report

    %for main_o in objects: <% print main_o.sale_announcement_ids %> %for o in announcement_pool.b ...

  4. springMVC3得知&lpar;五岁以下儿童&rpar;--MultiActionController

    Spring为了提供一个多动作控制器,您可以使用它的几个行动统一到一个控制器,这可以放在一起功能. 多动作控制器存在在一个单独的包中--org.springframework.web.mvc.mult ...

  5. 学习笔记&lowbar;ADB常用指令

    ADB 查看连接到计算机的Android设备或模拟器 adb devices 说明: 正常显示状态应该是IP:Port State. State=device说明设备已经连接到计算机, State=o ...

  6. npoi生成excel流并在客户端下载(html&plus;后台 )

    //前端页面 <body> <input type="button" value="导出Excel" class="button&q ...

  7. 我遇到的Spring的&commat;Value注解失效问题

    项目使用的是SSM体系,spring的配置如下,配置没问题,因为我发现其他文件中的@Value可以使用,只有一处@Value失效了. spring-servlet.xml <?xml versi ...

  8. css中的视距perspective和视差效果

    概述 之前觉得2个效果很叼,一个是3D翻转效果,另一个是视差效果.今天好好的研究一下,把心得记录下来,供以后开发时参考,相信对其他人也有用. 3D翻转 3D翻转效果其实非常简单,其实就是perspec ...

  9. nginx request&lowbar;time 和upstream&lowbar;response&lowbar;time

    1.request_time 官网描述:request processing time in seconds with a milliseconds resolution; time elapsed ...

  10. Applese走方格-dfs

    链接:https://ac.nowcoder.com/acm/contest/330/B来源:牛客网 题目描述 精通程序设计的 Applese 又写了一个游戏. 在这个游戏中,它位于一个 n 行 m ...