0x01 ANSI 和宽字符定义

	// ANSI 字符定义
CHAR varChar_1 = 'a'; // #typedef char CHAR
CHAR varChar_2[] = "ABCDEFG";
CHAR varChar_3[20] = "ABCDEFG"; // 宽字符定义
WCHAR varWChar_1 = L'a'; // #typedef wchar_t WCHAR
WCHAR varWChar_2[] = L"ABCDEFG";
WCHAR varWChar_3[20] = L"ABCDEFG";

0x02 字符串处理函数

  • 不安全的字符串处理函数
	CHAR buffer[10] = { 0 };                    // 初始化字符串
CHAR overflow[] = "AAAAAAAAAAAAAAAAAAAA"; // 造成溢出的数据
int BufferSize = 20; // 控制溢出的整数 memset(buffer, 0x41, BufferSize); // BufferSize 过大导致栈溢出
strcpy(buffer, overflow); // overflow 过大导致栈溢出
strcat(buffer, overflow); // overflow + buffer 的长度过大导致栈溢出
  • 安全的字符串处理函数
	CHAR buffer[10] = { 0 };        // 初始化字符串
CHAR overflow[] = "AAAAAAAAAAAAAAAAAAAAAA"; // 造成溢出的数据 errno_t res = NULL;
// strcpy_s
res = strcpy_s(buffer, overflow); // 只有两个参数,那么会自动检测 overflow 的大小是否超过 buffer
res = strcpy_s(buffer, 5, overflow); // 限制复制的大小为 5 个字节
// strcat_s
res = strcat_s(buffer, overflow); // 由于 overflow 大于 buffer,所以引发异常

异常如下

0x03 其他安全的字符串处理函数

	WCHAR Buffer[10] = L"AAAAAA";
WCHAR LinkBuffer[] = L"A";
STRSAFE_LPWSTR *DestEnd = NULL; // #typedef wchar_t *STRSAFE_LPWSTR
size_t size = NULL; // 安全的字符串拼接函数 StringCchCat
HRESULT res;
res = StringCchCat((STRSAFE_LPWSTR)Buffer, lstrlen(Buffer) + lstrlen(LinkBuffer) + 1, (STRSAFE_LPWSTR)LinkBuffer);
res = StringCchCatEx(
(STRSAFE_LPWSTR)Buffer, // 目标缓冲区
lstrlen(Buffer) + lstrlen(LinkBuffer) + 1, // 目标缓冲区大小,务必等于 Buffer + LinkBuffer + 1 的大小,1 为终止符
(STRSAFE_LPWSTR)LinkBuffer, // 源缓冲区,用于拼接至 Buffer 后
DestEnd, // Buffer 结尾的指针
&size, // 未使用的字符
STRSAFE_NO_TRUNCATION | STRSAFE_FILL_BEHIND_NULL // 如果函数成功,则使用dwFlags(0)的低字节来填充终止空字符后的pszDest的未初
// 如果函数失败,则pszDest不受影响。原始内容中没有添加任何内容
);
// cout << "DestEnd: " << DestEnd << endl;
// cout << "size: " << size << endl;
	WCHAR DestBuffer[10] = { 0 };
WCHAR SrcBuffer[] = L"AAAAAAAAA";
STRSAFE_LPWSTR *DestEnd = NULL;
size_t size = NULL;
HRESULT res;
res = StringCchCopy((STRSAFE_LPWSTR)DestBuffer, lstrlen(SrcBuffer) + 1, SrcBuffer);
res = StringCchCopyEx(
(STRSAFE_LPWSTR)DestBuffer, // 目标缓冲区
lstrlen(SrcBuffer) + 1, // 目标缓冲区大小,务必等于 Buffer + LinkBuffer + 1 的大小,1 为终止符
SrcBuffer, // 源字符串地址
DestEnd, // 源字符串结尾指正
&size, // 目标缓冲区未使用的字节
STRSAFE_NO_TRUNCATION | STRSAFE_FILL_BEHIND_NULL); // 如果函数成功,则使用dwFlags(0)的低字节来填充终止空字符后的pszDest的未初始化部分
// 与STRSAFE_NULL_ON_FAILURE的情况一样,如果函数失败,则pszDest设置为空字符串(TEXT(""))
/*
cout << "DestEnd: " << DestEnd << endl;
cout << "size: " << size << endl;
*/
	WCHAR DestBuffer[10] = { 0 };
HRESULT res;
res = StringCchPrintf((STRSAFE_LPWSTR)DestBuffer, sizeof(DestBuffer) / 2, TEXT("%d + %d = %d"), 1, 2, 3); STRSAFE_LPWSTR *DestEnd = NULL;
size_t size;
res = StringCchPrintfEx(
(STRSAFE_LPWSTR)DestBuffer, // 目标缓冲区
sizeof(DestBuffer) / 2, // 目标缓冲区大小
DestEnd, // 目标缓冲区结尾指针
&size, // 目标缓冲区未使用的字符数
STRSAFE_NO_TRUNCATION | STRSAFE_FILL_BEHIND_NULL, // 如果函数成功,则使用dwFlags(0)的低字节来填充终止空字符后的pszDest的未初始化部分
// 与STRSAFE_NULL_ON_FAILURE的情况一样,如果函数失败,则pszDest设置为空字符串(TEXT(""))
TEXT("%d + %d = %d"), 1, 2, 3 // 格式化字符
); if (res == S_OK)
{
cout << "有足够的空间可以将结果复制到pszDest而不进行截断,并且缓冲区以空值终止" << endl;
}
else if (res == STRSAFE_E_INSUFFICIENT_BUFFER)
{
cout << "cchDest 是 0 或比 STRSAFE_MAX_CCH 更大,或目标缓冲区是满的" << endl;
}
else if (res == STRSAFE_E_INVALID_PARAMETER)
{
cout << "由于缓冲区空间不足,复制操作失败" << endl;
}
#include <Windows.h>
#include <iostream>
#include <String.h>
#include <shlwapi.h>
#pragma comment (lib, "Shlwapi.lib")
using namespace std; int main(int argc, char *argv[])
{
LONGLONG var_1 = 521;
WCHAR Buffer[10] = { 0 }; // Buffer 初始化
// StrFormatKBSize 将数值转换为字符串,该字符串表示以千字节为单位表示的大小值
PTSTR res = StrFormatKBSize(
var_1, // 需要转换的数值
(PWSTR)Buffer, // 指向缓冲区的指针
sizeof(Buffer) / 2 // pszBuf的大小,以字符为单位
);
if (res == NULL)
{
cout << "调用失败" << endl;
}
else
{
cout << "字符串的地址: " << res << endl;
}
return 0;
}
	WCHAR String1[] = L"ABCDEFG"; // 定义两个相等的字符串
WCHAR String2[] = L"AbCdEfG";
int res = CompareStringEx(
LOCALE_NAME_SYSTEM_DEFAULT, // 设置为当前操作系统区域设置的名称
NORM_IGNORECASE | NORM_IGNORESYMBOLS, // 忽略大小写 | 忽略符号和标点符号
(LPCWCH)&String1, // 用于比较的字符串 1
sizeof(String1) / 2, // 用于比较的字符串 1 的大小
(LPCWCH)&String2, // 用于比较的字符串 2
sizeof(String2) / 2, // 用于比较的字符串 2 的大小
NULL, // 保留位,必须设置为 NULL
NULL, // 同上
0 // 同上
);
if (res != 0) // CompareStringEx 调用失败返回则 0
{
switch (res)
{
case CSTR_LESS_THAN:
cout << "lpString1指示的字符串的词汇值小于lpString2指示的字符串" << endl; break;
case CSTR_EQUAL:
cout << "由lpString1指示的字符串在词汇值中等效于由lpString2指示的字符串" << endl; break;
case CSTR_GREATER_THAN:
cout << "lpString1指示的字符串的词汇值大于lpString2指示的字符串" << endl; break;
}
}
else
{
DWORD error = GetLastError();
if (error == ERROR_INVALID_FLAGS)
{
cout << "为标志提供的值无效: " << endl;
}
else if(error == ERROR_INVALID_PARAMETER)
{
cout << "任何参数值都无效: " << endl;
}
}
WCHAR String1[] = L"ABCDEFG";
WCHAR String2[] = L"AbCdEfG";
int res = CompareStringOrdinal((LPCWCH)String1, sizeof(String1) / 2, (LPCWCH)String2, sizeof(String2) / 2, TRUE);// TRUE 为不区分大小写的比较
if (res != 0)
{
switch (res)
{
case CSTR_LESS_THAN:
cout << "lpString1指示的值小于lpString2指示的值" << endl; break;
case CSTR_EQUAL:
cout << "lpString1指示的值等于lpString2指示的值" << endl; break;
case CSTR_GREATER_THAN:
cout << "lpString1指示的值大于lpString2指示的值" << endl; break;
}
}
else
{
DWORD res = GetLastError();
if (res == ERROR_INVALID_PARAMETER)
{
cout << "任何参数值都无效" << endl;
}
}
	CHAR BeforeConversion[] = "ABCDEFG";
WCHAR AfterConversion[10] = { 0 };
int res = MultiByteToWideChar(
CP_ACP, // ANSI 代码页
NULL, // 影响读音符号的字符,一般设置为 NULL
(LPCCH)BeforeConversion, // 需要转换的 ANII 字符
-1, // 自动计算函数大小
(LPWSTR)AfterConversion, // 转换过后的字符串缓冲区
sizeof(AfterConversion) // 转换过后的字符串缓冲区的大小
);
if (res == 0) // 函数调用失败返回 0
{
cout << "转换失败" << endl;
}
	WCHAR BeforeConverion[] = L"ABCDEFG";
CHAR AfterConversion[10] = { 0 };
CHAR DefaultChar = '*';
BOOL UserDefaultChar = NULL;
int res = WideCharToMultiByte(
CP_UTF8, // 使用 CP_UTF8 代码页完成从宽字节到多字节的转换
NULL, // 一般为 NULL
(LPCWCH)BeforeConverion, // 需要转换的字符串的地址
-1, // 自动计算转换字符串的大小
(LPSTR)AfterConversion, // 转换完成时字符串储存地址
sizeof(AfterConversion), // 储存地址大小
(LPCCH)DefaultChar, // 遇到无法转换的字符时用什么代替
(LPBOOL)UserDefaultChar // 转换成功返回 FALSE,有一个或者多个字符无法转换时设置为 TRUE
);
if (res != 0 && UserDefaultChar == FALSE)
{
cout << "转换成功" << endl;
}
else // 调用之后返回 0 表示失败
{
switch (res)
{
case ERROR_INSUFFICIENT_BUFFER:
cout << "提供的缓冲区大小不够大,或者错误地设置为NULL" << endl; break;
case ERROR_INVALID_FLAGS:
cout << "为标志提供的值无效" << endl; break;
case ERROR_INVALID_PARAMETER:
cout << "任何参数值都无效" << endl; break;
case ERROR_NO_UNICODE_TRANSLATION:
cout << "在字符串中找到无效的Unicode" << endl; break;
}
}
  • IsTextUnicode(用于判断是 ANSI 字符还是宽字节字符)
	CHAR JudgeStr[] = "ABCDEFG"; // 测试字符串
int Result = IS_TEXT_UNICODE_REVERSE_MASK; // 是否包含宽字界字符标志位
BOOL res = IsTextUnicode((const void *)JudgeStr, sizeof(JudgeStr), (LPINT)&Result);
if (res != 0)
{
cout << "包含宽字节字符" << endl;
}
else
{
cout << "为 ANSI 字符" << endl;
}

Windows核心编程笔记之处理字符串的更多相关文章

  1. Windows核心编程笔记之进程

    改变进程基址,获取进程基址 #include <Windows.h> #include <iostream> #include <strsafe.h> #inclu ...

  2. Windows核心编程笔记之内核对象

    0x01 子进程继承父进程内核对象句柄 父进程 #include <Windows.h> #include <iostream> #include <strsafe.h& ...

  3. Windows核心编程笔记之错误处理

    0x01 GetLastError() 函数用于获取上一个操作的错误代码 #include <Windows.h> #include <iostream> using name ...

  4. Windows核心编程笔记之作业

    创建作业,并加以限制 HANDLE WINAPI CreateJob() { BOOL IsInJob = FALSE; DWORD ErrorCode = NULL; // 不能将已经在作业中的进程 ...

  5. 《Windows核心编程》读书笔记 上

    [C++]<Windows核心编程>读书笔记 这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对 ...

  6. C++Windows核心编程读书笔记

    转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...

  7. 【转】《windows核心编程》读书笔记

    这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入 ...

  8. windows核心编程---第二章 字符和字符串处理

        使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...

  9. Windows核心编程第二章,字符串的表示以及宽窄字符的转换

    目录 Windows核心编程,字符串的表示以及宽窄字符的转换 1.字符集 1.1.双字节字符集DBCS 1.2 Unicode字符集 1.3 UTF-8编码 1.4 UTF - 32编码. 1.5 U ...

随机推荐

  1. 『力荐汇总』这些 VS Code 快捷键太好用,忍不住录了这34张gif动图

    之前写过三篇文章,收获了极其不错的阅读量与转发量: 你真的会用 VS Code 的 Ctrl.Shift和Alt吗?高效易用的快捷键:多光标.跳转引用等轻松搞定 VS Code 中的 Vim 操作 | ...

  2. STM32F103VET6-keil工程配置-USART串口中断

    1.新建一个标准空白工程 2.设置时钟源为外部HSE时钟 1 #ifndef __SYSCLK_CONFIG_H 2 #define __SYSCLK_CONFIG_H 3 #include &quo ...

  3. MySQL基础知识:创建MySQL数据库和表

    虚构一个微型在线书店的数据库和数据,作为后续MySQL脚本的执行源,方便后续MySQL和SQL的练习. 在虚构这个库的过程中,主要涉及的是如何使用命令行管理 MySQL数据库对象:数据库.表.索引.外 ...

  4. SpringMVC-06 Ajax

    SpringMVC-06 Ajax Ajax 1.简介 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 是一种在无 ...

  5. 单链表及基本操作(C语言)

    #include <stdio.h> #include <stdlib.h> /** * 含头节点单链表定义及基本操作 */ //基本操作函数用到的状态码 #define TR ...

  6. [SDOI2009] HH的项链(待续)

    [SDOI2009] HH的项链(待续) 题目大意:对一个由若干个数字(可重复)组成的数列,询问\([l,r]\)中出现的不同的数字数量 考试时(考试时范围小)用的暴力,but,没有考虑数字0的情况, ...

  7. HDU_6693 Valentine's Day 【概率问题】

    一.题目 Valentine's Day 二.分析 假设$ s_0 $代表不开心的概率,$ s_1 $代表开心一次的概率. 那么随便取一个物品,那么它的开心概率为$ p _i $,可以推导加入之后使女 ...

  8. CSS中的块级元素,行内元素,行内块元素

    博客转载于:https://blog.csdn.net/swebin/article/details/90405950 块级元素 block 块级元素,该元素呈现块状,所以他有自己的宽度和高度,也就是 ...

  9. 让 Java 中 if else 更优雅的几个小技巧

    对于一个高级 crud 工程师‍而言,if else 是写代码时使用频率最高的关键词之一,然而有时过多的 if else 会让我们优雅的 crud 代码显得不那么优雅,并且感到脑壳疼

  10. 使用 DD 命令制作 USB 启动盘

    Windows 下有很多很好用的 USB 启动盘制作工具,比如 Rufus,但是 MacOS 下这个类型的工具就少了很多,这里记录下在 MacOS 中用 DD 命令制作 Linux USB 启动盘的操 ...