第二章:字符串和字符串处理

来源:互联网 发布:阿里云服务器加硬盘 编辑:程序博客网 时间:2024/05/21 00:01

1. char(表示8ANSI),wchar_t(表示16位的Unicode字符,而且由于早期版本的编译器没有提供这个内建的数据类型,所以编译器只有在指定了/zc:wchar_t编译开关时才会定义这个数据类型,默认是指定的.)
说明:在编译器内建对wchar_t的支持之前,有一个C头文件定义了一个wchar_t数据类型,如下所示:           typedef    unsigned     short       wchar_t;

wchar_t   c=L’A’;//L表示在编译器该字符串应该编译为Unicode字符串.

2. 任何修改字符串的函数都存在一个安全隐患:如果目标字符串的缓冲区不够大,无法容纳所生成的字符串,就会导致内存中的数据被破坏.在应用程序中包含strSafe.h,string.h也会包含进来.C运行库中现有的字符串处理函数(_tcscpy宏后的那些函数)已经标记为废弃不用.如果使用了这些函数,编译器就会发出警告(注意:必须在包含其他所有文件之后才包含StrSafe.h),每个函数都有一个对应的新版本函数.前面的名称相同,但是在最后添加_s(例如:_tcscpy相对应的_tcscpy_s)

3. C运行时实际上允许提供自己的函数,这样一来,在他检测到了一个无效参数时就会调用此函数.然后在函数中记录失败,附上一个调试器,或者做其他我们想做的事情.为了启动这个功能,必须先定义好一个函数,原型如下:

         void  InvalidParameterHandler(PCTSTR  expression,PCTSTR  Function,

                                     PCTSTR  file,unsigned  int  line,uintptr_t/*pReserved*/)

其中:expression描述了C运行时实现代码中可能出现的函数调用失败.Functionflieline分别描述了出现错误的函数名称、源代码文件和源代码行号.

  然后调用_set_invalid_parameter_handler来注册这个处理程序.

  最后在应用程序的开始调用_CrtSetReportMode(_CRT_ASSERT,0);从而禁止可能有C运行时触发的所有Assertion对话框.

4. C运行库新增了一些用户在执行字符串处理时提供更多控制的函数.其返回值为HRESULT.

HRESULT

描述

S_OK

成功,目标缓冲区中包含源字符串,并以/0结尾

STRSAFE_INVALID_PARAMETER

失败,NULL传给了一个参数

STRSAFE_INSUFFICIENT_BUFFER

失败,指定目标缓冲区太小,无法容纳整个源字符串

_countof宏来获取字符数,sizeof获取字节数.

5. 我们如果要比较字符串是否相等或者进行排序.较好的函数是:CompareString(Ex)CompareStringOrdinal.对于需要以符合用户语言习惯的方式向用户显示的字符串更是如此.

int CompareString( LCID locale,// 指定区域设置ID,使用GetThreadLocale()来获取

                                               DWORD dwCmdFlags,//标志位,用于修改函数在比较字符串时采用的方法

                                               PCTSTR  pString1,//字符串1

                                               int  cch1,//字符串1的字符数

                                               PCTSTR  pString2,//字符串2

                                               int  cch2)//字符串2的个数

其中dwCmdFlags的取值有:

标志

含义

NORM_IGNORECASE

LINGUISTIC_IGNORECASE

忽略大小写

NORM_IGNOREKANATYPE

不区分平假名和片假名字符

NORM_IGNORENONSPACE

LINGUISTIC_IGNOREDIACRITIC

忽略non-spacing字符

NORM_IGNORESYMBOLS

忽略符号

NORM_IGNOREWIDTH

不区分同一字符串的单字节和双字节形式

SORT_STRINGSORT

将标点符号当作符号来处理

为了比较程序内部所用的字符串(如路径名、注册表项值、xml元素/属性等),应该使用CompareStringOrdinal(PCWSTR  pString1,

                     int  cchCount1,

                     PCWSTR              pString2,

                     int  cchCount2,

                     BOOL     reCase)//由于这个函数执行的是码位比较,不考虑区域设置,所以速度很快.

以上两个函数的返回值:0:表示函数调用失败,

 返回值为CSTR_LESS_THAN(定义为1)表明pString1小于pString2

 返回值为CSTR_EQUAL(定义为2)表明pString1等于pString2

 返回值为CSTR_GREATER_THAN(定义为3)表明pString1大于pString.

为了方便起见,如果函数成功,我们可以从返回值中减去2,从而使得结果与C运行库函数的结果值(-1,0,1)保持一致.

6. 应用程序字符处理遵循的原则如下:

       开始将文本字符串想象为字符的数组,而不是char或者字节的数组

       用通用数据类型(TCHAR/PTSTR)来表示文本字符和字符串

       用明确的数据类型(BYTEPBYTE)来表示字节,字节指针和数据缓冲区

       TEXT_T宏来表示字面量字符和字符串,但为了保存一致性和更好的可读性,请避免两者混用.

       执行全局替换(PTSTR替换PSTR)

       修改与字符串相关的计算.可以使用宏来避免犯错:

                     #define  chmalloc(nCharactes)   (TCHAR*) malloc(nCharacters * sizeof(TCHAR))

  避免使用printf系列函数,尤其是不要用%s%S字段类型来进行ANSIUnicode字符串之间的相互转换.正确的做法是使用MultiByteToWideCharWideCharToMultiByte函数.

  Unicode_UNICODE符号要么同时指定,要么都不指定.

7. 对于字符串处理函数,应该遵循以下基本准则:

       始终使用安全的字符串处理函数,比如后缀为_s的函数.或者使用前缀为StringCch的函数.后者主要在我们想明确控制截断的时候使用.

       不要使用不安全的C运行库字符串处理函数.

       利用/GS/RTCs编译器标志来自动检测缓冲区溢出.

       不要使用Kernel32方法来进行字符串处理(lstrcat)

       在应用程序的代码中,需要要比较两种字符串.其中程序字符串包含文件名,路径,XML元素/属性以及注册表项/值等.对于这些字符串,应使用CompareStringOrdinal来进行比较.用户字符串则一般要在用户界面上显示,对于这些字符串,应使用CompareString(Ex)来比较.

8. UnicodeANSI字符串转换函数:

         int  MultiByteToWideChar(

                            UINT      uCodePage,//标识了与多字节字符串关联的一个代码页值

                            DWORD  dwFlags,//允许我们进行额外的控制,它会影响带变音符号.一般为0

                            PCSTR       pMultiByteStr,//指定要转换的字符串

                            int            cbMultiByte,//指定字符串的长度(字节数),如果为-1,则自动判断源字符串的长度

                            PWSTR     pWideCharStr,//写入内存缓冲区

                            int            cchWideChar);//缓冲区字符长度(字符数),如果传递0,则函数不会执行//转换,而是返回一个宽字符数,(包括终止字符’/0’)只有当缓冲区能够容纳该数量的宽字符时转换才成功

一般的步骤如下:

     调用MultiByteToWideCharpWideCharStr参数传入NULL,cchWideChar参数传入0,cbMultiByte传入-1

     分配一块足以容纳转化后Unicode字符的内存,大小是上次调用函数的返回值乘以sizeof(wchar_t)

     再次调用MultiByteToWideChar,这一次将缓冲区的地址作为pWideCharStr参数的值传入,将第一次得到的大小作为cchWideChar参数传入

     使用转换后的字符串

     释放Unicode字符串占用的内存块

int WideCharToMultiByte(

  UINT CodePage,            // code page

  DWORD dwFlags,            // performance and mapping flags

  LPCWSTR lpWideCharStr,    // wide-character string

  int cchWideChar,          // number of chars in string

  LPSTR lpMultiByteStr,     // buffer for new string

  int cbMultiByte,          // size of buffer

  LPCSTR lpDefaultChar,     // default for unmappable chars

  LPBOOL lpUsedDefaultChar  // set when default char used

);

其步骤与MultiByteToWideChar大致相同,只是在第二步不需要乘以sizeof(wchar_t)

注意:该函数的后两个参数,只有一个字符在uCodePage中指定代码页中没有对应的表示时才使用.在遇到一个不能转换的宽字符时,pDefaultChar用来指定字符(NULL,函数就会使用一个系统默认的字符,通常是?).

pfUsedDefaultChar指向一个布尔变量;在宽字符串中,如果至少有一个字符不能转换为对应的多字节的形式,则变量为TRUE,如果所有字符都能成功转换则设为FALSE(传入NULL).

9. BOOL IsTextUnicode(
  CONST VOID* pBuffer, // input buffer to be examined
  int cb,                // size of input buffer
  PINT      pResult               // options
);

包含的dll----AdvApi32.dll

包含.h-------WinBase.h

参数:pvBuffer,是一个void指针.

      cb表示字节数而非字符数,我们可以测试某部分字符就行了

      pResult:整数地址.指定函数执行哪些测试.如果为NULL,函数将执行他能执行的每一项测试.

返回值:Unicode返回TRUE.如果指定了具体的测试项目,那么函数在返回之前,还会shehi此整数中的相应位,一反应每个测试项目的结果.

注意此函数并不精确.