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. js--this指向的相关问题

    前言 关于this的指向问题是前端面试中常考的知识点,也是我们开发学习中较难理解的问题.作为JavaScript的基础,需要我们彻底理解这一关键词.this作为JavaScript中非常复复杂的机制, ...

  2. Codeforces Round #574 (Div. 2) D1. Submarine in the Rybinsk Sea (easy edition) 【计算贡献】

    一.题目 D1. Submarine in the Rybinsk Sea (easy edition) 二.分析 简单版本的话,因为给定的a的长度都是定的,那么我们就无需去考虑其他的,只用计算ai的 ...

  3. subprocess如何设置命令超时时间

    一.subprocess如何设置命令超时时间 最近遇到一个问题,就是我需要在服务器上执行某些shell命令,但是有些命令失败的时候是不会自动终止的,只会一直停在那里,很耗时间. 因此想到了设置超时时间 ...

  4. 2018年11月16日SQL Server实验内容(触发器实验)

    --注意:先把studentmanager数据库中的所有表用select into命令复制一份, --然后用复制后新表完成下面的实验,同时,对每个触发器都要进行验证. select *into dep ...

  5. (二)SpringBoot启动过程的分析-环境信息准备

    -- 以下内容均基于2.1.8.RELEASE版本 由上一篇SpringBoot基本启动过程的分析可以发现在run方法内部启动SpringBoot应用时采用多个步骤来实现,本文记录启动的第二个环节:环 ...

  6. Hi3559AV100 NNIE开发(7) Ruyistudio 输出mobileface_func.wk与板载运行mobileface_chip.wk输出中间层数据对比

    前面随笔讲了关于NNIE的整个开发流程,并给出了Hi3559AV100 NNIE开发(5)mobilefacenet.wk仿真成功量化及与CNN_convert_bin_and_print_featu ...

  7. 201871030106-陈鑫莲 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 班级博客 这个作业要求链接 作业要求 我的课程学习目标 1.学会结对学习,体会结对学习的快乐2.了解并实践结对编程 3.加深对D{0-1}问题的解法的理解4.复习并熟悉P ...

  8. 安装Dynamics CRM Report出错二

    提示账户不是本地用户且不受支持 找到所需的服务,使用域管理员用户更改服务运行的账户.应用和确定 重新启动服务 重新运行安装向导,环境验证成功

  9. Java(100-113)【类与对象、封装、构造方法】

    1.对象的创建以及使用 Student stu =new Student(); 根据一个类创建一个对象 导包.创建.使用 2.手机练习 有main才能run Phone.java package cn ...

  10. 自定义grub主题

    1 概述 自定义grub引导菜单的主题,笔者的linux是deepin,感觉默认的grub主题不太好看,嗯,没办法,就是想改了. 这篇文章主要是修改/boot/grub/grub.cfg以及/boot ...