字符与字符串操作——Windows via C/C++

在最新版的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cmd常用命令总结

CMD命令:开始->运行->键入cmd或command(在命令行里可以看到系统版本、文件系统版本)chcp 修改默认字符集chcp 936默认中文chcp 650011. appwiz.cpl:程序和功能 2. calc:启动计算器 5. ch…

生产者-消费者模式的实现

// 生产者-消费者模式 无锁队列 get()时&#xff0c;如果deque里面没有元素了&#xff0c;则会一直阻塞,还有待改进的空间 template <class T> class BlockingQueue { public:explicit BlockingQueue() : shutdown_(false) {}~BlockingQueue() {}void put(const T&a…

《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(13)--- 线程安全接口和双检查加锁优化...

4.3线程安全接口&#xff08;Thread-Safe Interface&#xff09;1.问题多线程组件通常包括多个可被公共访问的接口方法以及可以改变组件状态的私有方法。为了避免出现竞争条件&#xff0c;可以使用一个组件内部的锁对访问其状态的接口方法调用串行化。尽管当每个方法都自包容的…

C++流的基本概念

在C语言中&#xff0c;数据的输入和输出&#xff08;简写为I/O&#xff09;包括对标准输入设备键盘和标准输出设备显示器、对在外存磁盘上的文件和对内存中指定的字符串存储空间&#xff08;当然可用该空间存储任何信息&#xff09;进行输入输出这三个方面。对标准输入设备和标…

天哪,flash cs4可以使动态文本旋转了

天哪&#xff0c;flash cs4可以使动态文本旋转了. 只要使用rotationZ属性即可。 这可是解决了一个跨世纪的问题&#xff0c;爽爽爽。 啊哈哈哈。 这是测试源代码。 var rTextField:TextFieldnewTextField();var textFormat:TextFormatnewTextFormat();rTextField.text"…

Java编译过程(传送门)

我不是要做一门编程语言&#xff0c;了解这个对我现在的工作也没什么帮助&#xff0c;纯粹好奇而已。 传送门转载于:https://www.cnblogs.com/flying607/p/10481239.html

Linux 系统如何调整时区和时间

比如我要吧机器调成太平洋时区&#xff0c;那么我可以输入以下的命令&#xff0c;我们创建一个Link文件来指明是Pacific Time&#xff1a; cd /etc/ rm –r localtime sudo ln -s /usr/share/zoneinfo/US/Pacific localtime 调节完时区之后&#xff0c;接下来就是设置时间&a…

C语言typedefine 和define的区别

define &#xff1a; 宏定义&#xff0c;在预编译阶段就进行处理&#xff0c;简单的字符串代换&#xff0c;typedefine&#xff1a; 编译时进行处理&#xff0c;不是简单的替换&#xff0c;而是对类型说明符的重新命名。被命名的标识符具有类型说明的功能&#xff0c;代码说明#…

博客园“图灵杯”第3届博问大赛比赛结果

经过近一个月的激烈角逐&#xff0c;博客园“图灵杯”第三届博问大赛已圆满结束。获奖园友分别是&#xff1a; 一等奖&#xff1a;邀月&#xff08;奖励图灵图书4本&#xff09; 二等奖&#xff1a;Kinglee、邢少&#xff08;奖励图灵图书2本&#xff09; 三等奖&#xff1a;Gr…

Objective-C优缺点

优点&#xff1a; 1&#xff1a;Category&#xff0c;使用category可以在不改变原来类的同时为类增加新的方法或者重写原来类的方法实现&#xff08;使用runtime方法还可以在分类中实现方法交换和添加属性操作&#xff09; 2&#xff1a;运行时 动态识别&#xff0c;动态添加方…

C++输入一个字符串,去掉这个字符串中出现次数最少的字符 例如: 输入:abcabbc 输出:bbb

统计字符的个数&#xff0c;记录出现最少的字符&#xff0c;然后再输出#include <iostream>using namespace std;int main() {char str[100];cin >> str;// 统计字符大小int count[256] {0};char *p str;while (*p ! \0){count[*p];p;}// 记录出现最少的字符 出现…

Jmeter测试监控 Summary Report界面

Jmeter测试监控 Summary Report界面 这几天使用了JMeter测试数据库在进行点查询时的读写性能&#xff0c;从网上找到了该篇文章用于备份。 所有数据写入一个文件&#xff1a;保存测试结果到本地。 文件名&#xff1a;指定保存结果。 仅日志错误&#xff1a;仅保存日志中报错…

我的LINUX学习之路之二十一之web服务器简单搭建

今天说说如何搭建HTTP服务器&#xff01; 目的&#xff1a; 使用“多IP地址”方法实现多个网站。 使用“主机头名”方法实现多个网站。 使用“多端口”方法实现多个网站。 这回用图形界面来&#xff0c;不用说&#xff0c;先来看安装软件&#xff01; System-Administation-添加…

公务员级别分类

公务员领导职务层次与级别的对应关系 (一)国家级正职&#xff1a;一级(二)国家级副职&#xff1a;四级至二级(三)省部级正职&#xff1a;八级至四级(四)省部级副职&#xff1a;十级至六级(五)厅局级正职&#xff1a;十三级至八级(六)厅局级副职&#xff1a;十五级至十级(七)县处…

iOS性能优化篇 —— 耗电优化总结

手机App耗电的主要来源有以下四个因素&#xff1a; CPU处理&#xff0c;Processing网络&#xff0c;Networking定位&#xff0c;Location图像&#xff0c;Graphics耗电优化最终目的&#xff1a;通过尽可能降低CPU、GPU功耗来降低手机电量消耗。 尽可能少用定时器&#xff1b;优…

Versant 对象型数据库

引用&#xff1a;http://www.versant.com.cn/vision.aspx 对象数据库&#xff0c;可能比传统数据库快几十倍&#xff0c;收费&#xff0c;等测试 在几十万的数据库&#xff0c;找任一两个数据关系&#xff0c;不用比较

找出一个数组中唯一一个出现2次的数字

找出一个数组中唯一一个出现2次的数字&#xff0c;不清楚是不是LeetCode上的题。本人默认是LeetCode上的题。 一个数组中有N个数字&#xff0c;但是只有一个数字出现了2次&#xff0c;其他的数字均不相同。这种问题一般应该采用hash方法实现。 让所有的数字都放到一个unorder…

c语言fgets函数的用法

fgets()函数用于从文件流中读取一行或指定个数的字符&#xff0c;其原型为&#xff1a;char * fgets(char * string, int size, FILE * stream);参数说明&#xff1a; string为一个字符数组&#xff0c;用来保存读取到的字符。 size为要读取的字符的个数。如果该行字符数大于si…

.Net 中的反射(查看基本类型信息) - Part.2

转自&#xff1a;http://www.cnblogs.com/JimmyZhang/archive/2008/02/17/1071372.html 反射概述 和Type类 1.反射的作用 简单来说&#xff0c;反射提供这样几个能力&#xff1a;1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata)&#xff1b;2、迟绑定(Late-Bin…

clientHeight , scrollHeight , offsetHeight之间的区别及兼容方案

clientHeight , scrollHeight , offsetHeight之间的区别及兼容方案&#xff1a;https://www.cnblogs.com/nanshanlaoyao/p/5964730.html height、clientHeight、scrollHeight、offsetHeight区别 &#xff1a;https://www.cnblogs.com/yi-mi-yangguang/p/6211305.html 转载于:h…