使用vc编程时项目--》属性--》常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集。一般情况下说Unicode都是指UTF-16。也就是说每个字符编码为两个字节。65535个字符可以表示世界上大部分的语言。为了软件使国际化大家再编程时应该使用unicode字符集。由于原来学过c语言,不习惯使用Unicode,为了省事而直接在配置属性里调为多字节字符集,这是个不好的习惯。C语言的字符串,以及对这些字符串操作的函数都是不安全的。很容易导致缓冲区溢出错误,有时这会导致很严重的后果。所以极力建议大家要使用Unicode字符串,对它们进行的操作要使用接下来将要介绍的安全字符串函数。除此之外这对于提高性能也有帮助,因为现在大部分的windowsAPI都是直接对Unicode字符串进行操作,你所传入的多字节字符串会先转换为Unicode后再拿来使用。直接使用Unicode省略了转换的步骤,当然具有更高的性能。
C语言定义字符时使用的char类型,表示一个8位ANSI字符。
在vc中,microsoft定义了一个内置的数据类型wchar_t,它表示一个16位的Unicode字符。它是通过下面的语句定义的:
typedef unsigned short wchar_t;
很明显它占16位。定义Unicode字符与ANSI类似。如:
wchar_t a=L'a';
wchar_t array[100]=L"Hello world!!!";
对于array数组,它的每个字符都占16位且是以16位的\0结尾。
字符和字符串前的L是一个宏。它通知编译器应该将其编译为Unicode字符串。当编译器将此字符串放入程序的数据段时,会使用UTF-16来编码每个字符。
刚开始接触windows开发的同学会对windows提供的各种内置类型不知所措。其实这是windows为了显示出自己的与众不同将原来大家熟悉的c语言的内置类型起个别名罢了。如
typedef char CHAR;
typedef wchar_t WCHAR;
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef COSNT CHAR *PCSTR;
typedef WCHAR *PWCHAR;
typedef WCHAR *PWSTR;
typedef COSNT WCHAR *PCWSTR;
其实使用哪种数据类型并不重要,关键是能保持一致性。不要混合使用。如果是windows程序员最好能与windows保持一致。这可以增强代码的可读性。
为什么编译器能根据我们的设置自动为我们选择字符集呢。原来在本章开始时当我们选择使用Unicode字符集时,编译器会为我们在源文件中定义Unicode。形如#define Unicode。如果选择使用多字节字符集时会将定义Unicode的语句注释掉。为什么仅仅使用一句话就可以有这么大改变呢。请接着往下看:
#define UNICODE
typedef WCHAR TCHAR,*PTCHAR , PTSTR;
typedef COSNT WCHAR *PCTSTR;
#define _TEXT(quote) L##quote
#else
typedef CHAR TCHAR ,*PTCHAR,PTSTR;
typedef CONST CHAR *PCTSTR;
#define _TEXT(quote) quote
#endif
#define TEXT(quote) _TEXT(quote)
原来编译器使用预编译宏来进行判断,如果定义了UNICODE,就会将WCHAR定义为TCHAR,在_TEXT,在TEXT的参数前加上L。否则将TCHAR定义为CHAR,TEXT,_TEXT的参数前没有添加任何东西。明白了这些我们就应该清楚如何写出兼容性强的代码,也就是说让我们的代码在Unicode或是多字节字符集下都可以成功运行。或许你应经看出来了,使用TCHAR和TEXT。如:
TCHAR c=TEXT('a');
TCHAR array[100]=TEXT("Hello world!");
编译器会根据我们的设置,编译成不同的代码。在Unicode环境下,由于定义了UNICODE上述宏经过展开后会生成以下代码:
WCHAR c=L'a';
WCHAR array=L"Hello world!";
而在ANSI字符集下会生成这样的代码:
CHAR c='a';
CHAR array="Hello world!";
能看懂上述宏定义很重要,因为在vc中我们使用的DEBUG和RELEASE模式就是使用上述方法轻松转换的。当我们选择DEBUG模式时编译器会在源代码中定义_DEBUG。RELEASE模式时会定义NDEBUG。预编译指令会对上述定义进行判断,根据定义的不同生成不同的代码。对上述宏不懂得同学可以找下介绍宏的资料来看,宏参数、宏展开什么的。
正如前面介绍的,现在的windows版本内部处理字符串都是使用Unicode字符集,调用windows函数时如果传入的是一个ANSI字符串,函数首先会执行转换操作,将ANSI字符串转换为Unicode字符串。
如果一个windows函数参数列表中存在字符串,它通常有两个版本。一个接受Unicode字符串另一个接受ANSI字符串。比如大家比较熟悉的MessageBox,它就有两个版本,一个是MessageBoxA,处理ANSI字符串另一个是MessageBoxW用以处理Unicode字符串。既然MessageBox有两个版本为什么平时我们使用时只需要使用MessageBox就行了。这个还是跟宏定义有关。在windows提供的头文件中有这样一句话:
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
有了上面的介绍是不是这句话很容易的就看出来了。对了,MessageBox并不是真正的函数,它仅仅是一个宏罢了。根据是否定义UNICODE决定在源文件中使用哪个函数。很多函数都存在这样的情况。这也是很多新手在逆向工程函数拦截时使用如MessageBox却一无所获的原因。
当我们使用ANSI字符集时,UNICODE不会被定义,真正使用的是MessageBoxA函数,该函数首先执行将ANSI字符串转换为Unicode,然后再调用MessageBoxW函数。W版本返回的字符串也要先转换成ANSI字符串才被能被使用。与直接使用W版本相比这当然性能更低。
Windows的这种做法很好的兼容了Unicode和ANSI。可以考虑在我们自己的程序中使用这种方法。比如导出dll时,可以考虑导出两个函数一个ASNI版本,一个Unicode版本。ANSI版本仅执行字符串转换操作之后调用Unicode版本的函数。
以上介绍的都是windows系统处理Unicode和ANSI字符集的方法。作为一门语言C语言也提供了自己处理它们的机制。C运行库也提供了不同的函数处理不同的字符集,但是与windows不同的是c运行库的ANSI版本的函数不会在内部调用Unicode版本的函数。
如strlen用于处理ANSI字符集,返回字符串长度,与之对应的Unicode版本为wcslen。(wide character set)。
C语言提供的对字符串进行修改的函数存在安全隐患,容易造成缓冲区溢出。轻则结果错误,重则系统崩溃。因为它们对目标缓冲区进行操作时没有收到指定缓冲区的最大长度的参数,函数并不知道自己会破坏内存。Microsoft提供了一些新的安全的函数来取代C运行库不安全的字符串处理函数。虽然我们已经习惯使用strcpy,printf,strcat等这些函数,但是我们还是去要忘记它们,转而使用windows提供的这些的新的更安全的函数。所有要使用安全的函数程序必须包含StrSafe.h头文件。现有的每一个函数,如strcpy,_tcscpy都有一个对应的安全新版本函数,strcpy_s,_tcscpy_s。前面的名称相同但最后添加了一个_s,代表更安全。如老版本的函数的区别是它们需要目标缓冲区的大小。注意不是字符串所占的字节数,而是字符数,无论是ANSI字符还是Unicode字符集都可以使用宏_countof来得到字符数(使用sizeof不行哦,它返回字节数)。如果目标缓冲区不足以容纳结果数据,函数就会设置局部于线程的C运行时变量errno。然后返回一个errno_t值来指出成功或失败。关于安全函数仅仅介绍这么多,一者《windows核心编程》中关于此介绍的很简单且晦涩难懂。二者平时我们在开发时很少能够用到,只要知道每个对应的c字符串操作函数都对应着一个安全函数,用时再查也不迟。
现在再也不能将字符认为仅仅占一个字节了,因为存在Unicode的字符。要表示字节可以使用BYTE。建议平时使用通用的数据类型如TCHAR,PTSTR定义变量。同时将字符或字符串用TEXT或_T包括起来。
涉及到ANSI和Unicode字符集的转换可以使用以下两个函数:
MultiByteToWideChar和WideCharToMultiByte。
判断字符串是Unicode还是ANSI字符集可以使用函数IsTextUnicode。
- Windows核心编程第二章,字符串的表示以及宽窄字符的转换
目录 Windows核心编程,字符串的表示以及宽窄字符的转换 1.字符集 1.1.双字节字符集DBCS 1.2 Unicode字符集 1.3 UTF-8编码 1.4 UTF - 32编码. 1.5 U ...
- 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操作系统在全世界日益广泛的流行,对于软件开发人员来说,将目标瞄准国际上的各个不同市场,已经成为一个 ...
- Windows核心编程第一章.错误处理
Windows核心编程第一章,错误处理. 一丶错误处理 1.核心编程学习总结 不管是做逆向,开始做开发.在Windows下.你都需要看一下核心编程这本书.这本书确实写得很好.所以自己在学习这本书的同时 ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- [转]Windows Shell 编程 第二章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987893】
第二章Shell的结构 “Shell 编程”的大伞之下有大量的API函数和COM接口.这个种类繁多的‘命令’集允许你用不同的方法对Windows Shell进行编程.函数和接口并不是两种提供相同功能 ...
- windows核心编程-第一章 对程序错误的处理
第一章-对程序错误的处理 在开始介绍Microsoft Windows 的特性之前,必须首先了解 Wi n d o w s的各个函数是如何进行错误处理的. 当调用一个Wi n d o w s函数时,它 ...
- 《解读window核心编程》 之 字符和字符串处理方式
推荐的字符和字符串处理方式 開始将文本字符串想象为字符的数组,而不是 char 或字节的数组. 用通用数据类型(如 TCHAR/PTSTR )来表示文本字符和字符串. 用明白的数据类型(如 BYTE ...
- Windows核心编程 第二十章 DLL的高级操作技术
第2 0章 D L L的高级操作技术 看了下这章的内容,谈不上高级,都是些常用相关,但是还是有一些细节需要注意. 20.1 DLL模块的显式加载和符号链接 如果线程需要调用D L L模块中的函数,那么 ...
- windows核心编程---第一章 谈谈windows中的错误处理机制
我们写的函数会用返回值表示程序执行的正确与否,使用void,就意味着程序一定不会出错.Bool类型标识true时为真,false时为假.其他类型根据需要可以定义成不同意义. Win ...
随机推荐
- [课程设计]Scrum 2.5 多鱼点餐系统开发进度(下单一览页面-菜式添加框架设计)
Scrum 2.5 多鱼点餐系统开发进度 (下单一览页面-菜式添加框架设计) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题 ...
- 为什么要在html和body加上“height:100%;”
元素中有内容的时候div才能被撑起来所以我给div加了背景但是也不显示,就是因为没有内容,这个时候的解决办法就是 html,body{ height:100%; }
- 查看占用cpu和内存最多的进程
linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合: ps aux|head -;ps aux|grep -v PID|sort -rn -k +|head linux下获取占用内存 ...
- 17-underscore库(下)
一.函数介绍 1.bind 结构 _.bind(function, object, *arguments) 说明 一个对象中所有的成员函数的this都指向这个对象 举例 _.bind(function ...
- Java开发中经典的小实例-(比较输入数值的最大值、最小值和平均值)
//输入数字个数来产生数字并且比较大小 import java.util.Scanner;public class Test1 { public static void main(String ...
- 深入浅出设计模式——迭代器模式(Iterator Pattern)
模式动机 一个聚合对象,如一个列表(List)或者一个集合(Set),应该提供一种方法来让别人可以访问它的元素,而又不需要暴露它的内部结构.针对不同的需要,可能还要以不同的方式遍历整个聚合对象,但是我 ...
- Linux_命令_积累
1.ps 查看进程状态 ZC: "ps -a" 和 "ps a" 有区别... (具体查看 "man ps") 1.1.ps aux 1.2 ...
- mongoDB 数据导出与导入
一.导出 命令格式:在mongodb/bin目录下 mongoexport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 -f 字段 -q 条件导出 --csv ...
- 关于Jquery动画滞后问题(转)
jQuery中slideUp .slideDown.animate等动画运用时,如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行,其表现不雅.非常影响使用体验. ...
- java高薪之路__007_反射
参考地址: 1. http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html2. http://www.cnblogs.com/ ...