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. U盘重装系统:手把手教你怎么使用U盘重装系统、清除登录密码

    前言 之前讲过<不懂电脑也能自己重装系统,可视化傻瓜式一键重装系统不求人!!!>,这是针对可以正常开机的情况下直接使用浏览器功能重装系统, 那不能正常开机或者忘记密码的怎么办呢? 不慌,今 ...

  2. WorkSkill整理之 java用Scanner 类输入数组并打印

    输入不确定长度的数组 import java.util.*; public static void main(String[] args){ System.out.println("请输入一 ...

  3. POJ_1797 Heavy Transportation 【最大生成树的最小边】

    一.题目 POJ1797 二.分析 题意就是让你找到从1到n的一条路,由于边的最大称重限制,你需要确定限制的最小值,也就是能运输的最大值. 可以结合最小生成树想,利用并查集,然后不断更新答案即可,需要 ...

  4. ASP.NET Core中间件初始化探究

    前言 在日常使用ASP.NET Core开发的过程中我们多多少少会设计到使用中间件的场景,ASP.NET Core默认也为我们内置了许多的中间件,甚至有时候我们需要自定义中间件来帮我们处理一些请求管道 ...

  5. 从零学脚手架(六)---production和development拆分

    development.production拆分 根据文件拆分 webpack打包时分为开发模式(development)和发布模式(production),在前面使用命令参数做了简单区分. 但这种方 ...

  6. C#无边框窗体拖动代码

    1.重写 protected override void WndProc(ref Message m) { if (m.Msg == 163 && this.ClientRectang ...

  7. CMU15-455 Lab2 - task4 Concurrency Index -并发B+树索引算法的实现

    最近在做 CMU-15-445 Database System,lab2 是需要完成一个支持并发操作的B+树,最后一部分的 Task4 是完成并发的索引这里对这部分加锁的思路和完成做一个总结,关于 B ...

  8. Cai Xukun and Orz Pandas Gym - 102309C

    题目链接:https://vjudge.net/problem/Gym-102309C 题意:给定蔡徐坤投篮的位置和篮筐的位置以及最大初速度,求一个初速度和时间. 思路:一开始我以为要用到二分,后面仔 ...

  9. Ubuntu18.04美化(Mac OS主题) 美化小白专用

    本文主要针对第一次接触Ubuntu美化的童鞋们,有些啰嗦的地方大神勿喷 先上效果图 首先安装神器 gnome-tweak-tool 开启一个终端,输入 sudo apt install gnome-t ...

  10. java例题_32 取一个整数a从右端开始的4~7位

    1 /*32 [程序 32 左移右移] 2 题目:取一个整数 a 从右端开始的 4-7 位. 3 */ 4 5 /*分析 6 * 从右端开始的第四位相当于原数除以1000后结果的最后一位数, 7 * ...