在最新版的Windows, Windows Vista,它应该支持Unicode 5.0。在编程中对字符与字符串的操作是很普通的,为新的系统写代码,尽可能使用Unicode,它提供了更好的性能,以及可以进行区域化。而且与COM及.Net框架互操作时也有帮助。
缓冲区溢出是系统漏洞的重要来源,Microsoft对此提供的c-runtime中包含了一些新函数用于操作字符串。你应该都使用这些新函数。
在Windows Vista中,每个字符都用UTF-16(UTF是Unicode Transformation Format)进行编码,它是双字节的,这里我们所指的Unicode都指UTF-16编码。但是双字节还不能表示某些语言中的所有字符,对于这些语言,它支持代理(surrogates),后者是用32位代表一个字符。
还有另外一些UTF编码,常见的有:
UTF-8:它对一些字符用1byte,一些字符用2byte,一些字符用3或4byte表示。这种编码目前很流行。
UTF-32:它对每个字符都用4byte表示,这种表示法效率低,很少使用。

一. 数据类型
对于单字节与双字节字符,它定义分别如下:
char c='a';
char szBuffer[100] = "A string";

wchar_t c=L'a';
wchar_t szBuffer[100] = L"A string";
实际上,wchar_t是unsigned short类型,另外Microsoft还定义了CHAR, PCHAR, TEXT等类型和宏,这些都是条件定义的,它根据是否使用Unicode而决定合适的版本。这些定义可以在WinNT.h文件找到。

二. Unicode和ANSI函数
从Windows NT开始,所有的核心API函数都使用Unicode版本,所以都要求Unicode字符串。如果你传递的是ANSI字符串,则它要进行转换,它会消耗性能的。在之前的Windows版本,很多函数都提供两个版本:XXXW和WWWA,如CreateWindowExW和CreateWindowExA。到Vista,后者只是起一个转换层的作用。如果你需要建立DLL让别人使用,也可以考虑
同样,C-runtime也提供了Unicode版本的相应字符串函数,如strlen对应的wcslen(wc表示wide character)。但是尽管这样,c-runtime函数对于字符串操作是非常不安全的,如下:
WCHAR  szBuffer[3] = L"";
wcscpy(szBuffer, L"abc");
上面代码把四个字符拷贝到只有三个字符长的缓冲区中!这些代码是缓冲区溢出的最大根源。对此,Microsoft提供了安全字符串函数,它在strsafe.h(在Windows SDK中,而不在VC的目录中)中声明(这个头文件应该在最后包括,因为它使用了其它头文件)
PTSTR _tcscpy(PTSTR strDes, PCTSTR strSrc); //
errno_t _tcscpy_s(PTSTR strDes, size_t numChars, PCTSTR strSrc);

除了这些函数外,C运行时还提供了对字符串操作有更多控制的函数。如:
HRESULT StringCchCat(PTSTR pszDest, size_t cchDest, PCTSTR pszSrc);
HRESULT StringCchCatEx(PTSTR pszDest, size_t cchDest, PCTSTR pszSrc,
   PTSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags);

HRESULT StringCchCopy(PTSTR pszDest, size_t cchDest, PCTSTR pszSrc);
HRESULT StringCchCopyEx(PTSTR pszDest, size_t cchDest, PCTSTR pszSrc,
   PTSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags);

HRESULT StringCchPrintf(PTSTR pszDest, size_t cchDest,
   PCTSTR pszFormat, ...);
HRESULT StringCchPrintfEx(PTSTR pszDest, size_t cchDest,
   PTSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags,
   PCTSTR pszFormat,...);
在这些参数中,Cch表示Count of Characters。另外还有一个以Cb作为函数名的字符串操作函数集,这里Cb指Count of byte,如StringCbCat(Ex), StringCbCopy(Ex)。
在这些函数中,如果缓冲区太小,它不会完成功能并返回STRSAFE_E_INSUFFICIENT_BUFFER。在扩展版本的函数中(Ex),额外的参数的意思如下:
size_t* pcchRemaining: 目标缓冲区中未用字符的数目('\0'不计入),例如把一个字符拷贝到10长度的缓冲区中,就得到9。
LPTSTR* ppszDestEnd: 如果它非空,指向目标缓冲区的'\0'字符。
DWORD dwFlags: 一些枚举值组合。见SDK文档。

三. Windows字符串函数
Windows也提供了许多字符串操作函数,一些函数如lstrcat, lstrcpy等已经过时了,因为它们没有提供缓冲区溢出检测。另外ShlwApi.h还定义了许多格式化操作的字符串函数,特别是数字值,如StrFormatKBSize和StrFormatByteSize等。见MSDN。
比较字符中的操作很常见,这个任务最好调用CompareString(Ex)和CompareStringOrdinal:
int CompareString(
   LCID locale,
   DWORD dwCmdFlags,
   PCTSTR pString1,
   int cch1,
   PCTSTR pString2, int cch2);
它还区域信息作为比较依据,一般会取得正确的比较结果。这里LCID一般通过GetThreadLocale函数取得当前线程的区域ID。当然这个函数效率上会慢,对于比较程序性字符串,如参数,注册表键,XML元素属性等,可以使用CompareStringOrdinal,这不考虑区域信息。
要注意这两个函数返回值与C run-time的相应函数不同,它是1(CSTR_LESS_THAN), 2(CSTR_EQUAL)和3(CSTR_GREATER_THAN),你可以减2获得与c run-time相应的返回值。

四. 编程建议
1. 把字符串作为字符数组,而不是char数组或byte数组
2. 使用通用类型(TCHAR/PTSTR)表示字符和字符串
3. 对于字节,字节指针和数据缓冲区使用直接类型BYTE和PBYTE
4. 使用字符串和字符常量使用TEXT或_T宏
5. 进行全局替换,如用PTSTR替换PSTR
6. 修改字符串相关的数字运算问题,如用_countof(szBuffer)而不是sizeof(szBuffer)取得缓冲区的字符数。分配内存也用malloc(nch*sizeof(TCHAR))而不用malloc(nch),当然可以定义如下的宏:
#define chmalloc(nCharacters) (TCHAR*)malloc(nCharacters * sizeof(TCHAR))
7. 避免printf家族函数,特别是%s和%S类型的参数,具体见转换部分
8. 要指定UNICODE符号
下面是字符串操作函数的选择建议
1. 使用安全字符串版本(带_s后缀或StringCch前缀的)。不使用任何没有带目标缓冲区大小的缓冲区操作函数。c run-time提供了memcpy_s, memmove_s等函数使用
2. 利用/GS和/RTCs编译器选取项来自动检测缓冲区溢出问题
3. 不使用Kernel32中的字符串操作函数,如lstrcat, lstrcpy

五. 在Unicode和ANSI间转换
Windows函数MultiByteToWideChar提供了多字节字符(非Unicode的多字节字符)与Unicode字符的转换。
int MultiByteToWideChar(
   UINT uCodePage,
   DWORD dwFlags,
   PCSTR pMultiByteStr,
   int cbMultiByte,
   PWSTR pWideCharStr,
   int cchWideChar);
int WideCharToMultiByte(
   UINT uCodePage,
   DWORD dwFlags,
   PCWSTR pWideCharStr,
   int cchWideChar,
   PSTR pMultiByteStr,
   int cbMultiByte,
   PCSTR pDefaultChar,
   PBOOL pfUsedDefaultChar);

函数的使用过程一般如下:
1. 参数pWideCharStr传递NULL,cchWideChar参数传递0,cbMultiByte传递-1,这样调用就取转换后的字符数
2. 根据1返回的字符数(cc)分配内存块(cc*sizeof(wchar_t))
3. 再调用该函数,传入相应参数进行字符串转换
4. 释放2中产生的内存块

如果你需要编写两种类型的字符串都能操作的DLL函数,你也可以Microsoft一样提供XXXW和XXXA版本的函数,其中后者的实现在经过上面两个函数转换后传递给前一个函数的实现。如果要决定某个文件的字符是否是Unicode字符,可用IsTextUnicode函数:
BOOL IsTextUnicode(CONST PVOID pvBuffer, int cb, PINT pResult);
它声明于AdvApi32.dll中,但是这个函数是基于统计的,这样可能会返回一个不正确的结果。

转载于:https://www.cnblogs.com/Adon/archive/2009/10/11/Windows.html

字符与字符串操作——Windows via C/C++相关推荐

  1. c++ string 删除字符_字符串操作的全面总结(附完整代码)

    字符串操作看似简单,其实非常重要,不注意的话,经常出现代码运行结果和自己想要的不一致,甚至崩溃.本文总结了一些构建string对象方法.修改string对象的方法.string类型的操作函数.stri ...

  2. c++ string 删除字符_字符串操作的全面总结

    来自公众号:C语言与cpp编程 字符串操作看似简单,其实非常重要,不注意的话,经常出现代码运行结果和自己想要的不一致,甚至崩溃.本文总结了一些构建string对象方法.修改string对象的方法.st ...

  3. c语言字符串中的字符无效,字符串操作

    字符串主要用于编程,字符串在存储上类似字符数组,所以它每一位的单个元素都是可以提取的.字符串也有很多操作,在正文将对C语言.C++和java中对其操作进行介绍. 中文名 字符串操作 外文名 strin ...

  4. python设置字符_python字符串操作

    # FirstPython.py """ 标准字符串函数 """ """ 字符串索引 "" ...

  5. 有关UNICODE、ANSI字符集和相关字符串操作的总结[转]

    Q UNICODE字符串如何显示 A 如果程序定义了_UNICODE宏直接用 WCHAR *str=L"unicodestring"; TextOut(0,0,str); 否则就需 ...

  6. python day2 python基础 列表、元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码...

    本节内容 列表.元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 ...

  7. python字典编码_Python列表,字典,元组,字符串操作,文件操作,字符编码

    1. 列表操作 1.1 列表的定义: names = ["wangjing", "wangjun", "hashiqi"] names[0] ...

  8. java 字符串操作_Java 字符与字符串

    字符 // 定义字符 char c1 = 'a'; char c2 = '1'; char c3 = '中'; // 自动装箱 Character c = c1; // 自动拆箱 c1 = c; // ...

  9. day2 字符编码、列表、元组、字符串操作、字典

    文章目录 1.三元运算与字符串编码转换 2.列表.元组操作 3.字符串操作 4.字典操作 1.三元运算与字符串编码转换 三元运算 a,b,c = 1,3,5 d = a if a > b els ...

最新文章

  1. [JS] HEX颜色转换成RGBA
  2. 再见了SpringMVC,这个框架有点厉害,甚至干掉了Servlet!
  3. 多个相机拍摄定位_两种方式拍照易泄露隐私 | 如何避免照片记录 iPhone 定位信息?...
  4. 谈新公司的人才队伍建设
  5. windows下启动/关闭Sybase数据库服务器
  6. celeba数据集_人脸识别常用数据集介绍(附下载链接)及常用评估指标
  7. vim编写python_用vim写python代码
  8. 2011年三八妇女节搜索引擎LOGO设计欣赏
  9. Arch Linux下打不开gnome-shell
  10. 网管实战之使用RSA实现企业安全访问
  11. 3-1numpy基本操作
  12. java购物车商品排序_Java购物车
  13. Github Star 8.4K,超级好用的OCR数据合成与半自动标注工具,强烈推荐!
  14. Python 机器学习 随机森林 天气最高温度预测任务(二)
  15. 【C#】SQL数据库助手类2.0(自用)
  16. Android性能提升之强引用、软引用、弱引用、虚引用使用
  17. android nef转jpg格式文件,nef格式转换成jpg
  18. 廊坊金彩:店铺如何分析问题
  19. 勒索病毒基础介绍,值得收藏
  20. 上海航芯 | 全自动咖啡机设计方案

热门文章

  1. 数据库提示:正在还原中,无法访问 应该怎么办?
  2. 关闭 Pycharm 更新提示
  3. elementui vue的html随机点名器软件网页版源码1.1
  4. c#url拼接方法名_C# 从1到Core委托与事件
  5. 百度java的线程技术_自我提升(基础技术篇)——java线程简介
  6. erlang mysql性能瓶颈,Erlang Mysql:如何防止SQL注入
  7. redis——实战点赞
  8. 双向循环链表【数据结构】
  9. 游戏服务器架构-设计模式之观察者模式和发布订阅模式真的一样吗?
  10. C++实现md5加密或计算文件的唯一性识别