欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

读书笔记-Windows核心编程 字符与字符串处理

读书笔记-Windows核心编程 字符与字符串处理

先来道个歉,firfor,我当时发帖说“怕你这里有错。你再仔细看看代码,ebp+的是形参,ebp-的是局部变量。 ”其它的附加话都是无心说出来的,说话太过随意了,没想到让你产生了误解,先对你说声对不起。顺便自罚一下子。
以后坚持写读书笔记,这样理解快,自然掌握就快了。

  C语言用char数据类型来表示一个8位ANSI字符,默认情况下,在源代码中声明一个字符串时,C编译器会把字符串中的字符转换成由8位char数据类型构成的一个数组:
char c = ‘A’;
char szBuffer[100] = “Hello world”;
  Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16为的Unicode(UTF-16)字符。通过在字符串前加一个L来通知编译器该字符串应当编译为一个Unicode字符串。
wchar_t c = L’A’;
wchar_t szBuffer[100] = L”Hello world”;
  微软又将这些定义为自己的数据类型,在WinNT.h中。
typedef char CHAR;//8-bit
typedef wchar_t WCHAR;//16-bit
//8-bit
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR;
//16-bit
typedef WCHAR *PWCHAR;
typedef WCHAR *PWSTR;
typedef CONST WCHAR *PCWSTR;
  还有下面的宏和类型,使用这些宏和类型,无论是ANSI还是Unicode字符,都能通过编译,而且使用Windows数据类型,有利于增强代码的可读性。
#ifdef UNICODE
typedef WCHAR TCHAR,*PTCHAR,PTSTR;
typedef CONST 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)
  从Windows NT开始,Windows的所有版本都完全用Unicode来构建,也就是说,所有核心函数(创建窗口,显示文本,字符串处理等等)都需要Unicode字符串。调用Windows函数时,如果向它传入一个ANSI字符串(由单字节字符组成的一个字符串),那么函数首先会把字符串转换为Unicode,再把结果传给操作系统。如果希望函数返回ANSI字符串,那么操作系统会先把Unicode字符串转换为ANSI字符串,再把结果返回给我们的应用程序。所有这些转换都是在幕后进行的。执行这些字符串转换,系统会产生时间和内存上的开销。
  C运行库的Unicode函数和ANSI函数(新的安全字符串函数):
在这些新函数发布以前,任何修改字符串的函数都会存在一个安全隐患:如果目标字符串缓冲区不够大,无法容纳生成的字符串,就会导致内存中的数据被破坏。

str在栈中的高地址,当memcpy的操作导致tem溢出的时候就会覆盖掉高地址处的内存。

  于是这些新的安全函数便应运而生。现在每个函数(如_tcscpy或_tcscat)都有一个对应的新版本的函数。前面的名称相同,但最后添加了一个_s后缀,代表secure。所有这些新函数都有一个共同特征。在将一个可写的缓冲区作为参数传递时,必须同时提供它的大小。这个值应该是一个字符数,通过对缓冲区使用_countof宏,很容易计算这个值。
所有这些后缀为_s的安全函数的首要任务是验证传给它们的参数值。要检查的项目包括指针不为NULL,整数在有效范围内,枚举值是有效的,而且缓冲区足以容纳结果数据。如果这些检查中的任何一项失败,函数都会设置局部于线程的C运行时变量errno。然后,返回一个errno_t值来指出成功或失败。然而,这些函数并不实际返回。如果是一次调试版构建(debug),会显示一个Debug Assertion Failed对话框,然后终止应用程序。如果是发行版(release),则直接自动终止程序的运行。
  C运行时实际上允许我们提供自己的函数,这样这些函数在检测到一个无效的参数时,就可以调用我们的函数。在这个函数中,我们可以进一步对异常进行处理。为了实现此功能我们必须定义好一个函数,原型如下:
void _invalid_parameter(
   const wchar_t * expression,
   const wchar_t * function, 
   const wchar_t * file, 
   unsigned int line,
   uintptr_t pReserved
);
function,file,line,expression分别描述了出现了错误的函数名称,源代码文件,源代码行数,和代码中出现的错误描述。我们使用_set_invalid_parameter_handler来注册这个处理程序。我们还要在程序开头的地方调用_CrtSetReportMode(_CRT_ASSERT,0),禁用掉Debug Assertion Failed对话框,不然这个错误对话框依然会出现。这样我们就可以在程序中检查这个errno_t的返回值来判断函数执行是否成功。可能的返回值在errno.h中有定义。
下面看一个例子。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功