• Windows字符和字符串处理


    1.简介

    一直以来,我们将文本字符串编码成一组以0结尾的单字节字符,调用strlen,它就会返回“以0结尾的一个ANSI单字节字符数组”的字符数。

    但是,某些语言文字系统(如韩文)的字符集有非常多的符号,一个字节最多能表示256个符号,这是远远不够的;为了支持这些语言文字系统,双字节字符集出现了。双字节字符集中,一个字符串中的每个字符都由1个或2个字节组成。

    2.Unicode编码

    UTF全称是Unicode Transformation Format(Unicode转换格式),有以下几种格式。

    • UTF-8:将一些字符编码为1个字节、2个字节、3个字节、4个字节,相当流行的编码格式。
    • UTF-16:将每个字符编码为2个字节。
    • UTF-32:将每个字符都编码为4个字节。

    3.ANSI字符和Unicode字符

    C语言用char数据类型表示一个8位的ANSI字符。如下:

    1. char c = 'A';
    2. char buffer[100] = "string";

    微软的C/C++编译器定义了一个内建的数据类型wchar_t,表示一个16位的Unicode(UTF-16)字符。默认情况下,在vs中新建一个项目时,编译器会打开/Zc:wchar_t的开关,我们才能够正常使用这个数据类型。

    声明Unicode字符和字符串的方法。如下:

    1. wchar_t c = L'A';
    2. wchar_t buffer[100] = L"string";

    字符串之前的大写字母L通知编译器该字符串应当编译为一个Unicode字符串。

    为了与C语言区分,Windows希望定义了自己的数据类型。如下所示:

    1. typedef char CHAR;
    2. typedef wchar_t WCHAR; // wc, 16-bit UNICODE character

    除此之外,还定义了大量方便的数据类型。如下所示:

    1. typedef CHAR *PCHAR, *PSTR;
    2. typedef CONST CHAR *PCSTR;
    3. typedef WCHAR *PWCHAR, *PWSTR;
    4. typedef CONST WCHAR *PCWSTR;

    另外,在写代码的时候,可以使用ANSI或Unicode字符/字符串使能够通过编译。定义了以下类型的宏:

    1. #ifdef UNICODE // r_winnt
    2. typedef WCHAR TCHAR, *PTCHAR,PTSTR;
    3. typedef CONST WCHAR *PCTSTR;
    4. #define __TEXT(quote) L##quote // r_winnt
    5. #else
    6. typedef CHAR TCHAR, *PTCHAR,PTSTR;
    7. typedef CONST CHAR *PCTSTR;
    8. #define __TEXT(quote) quote // r_winnt
    9. #endif /* !_TCHAR_DEFINED */
    10. #define TEXT(quote) __TEXT(quote)

     利用这些类型和宏,无论使用ANSI还是Unicode字符,都能通过编译。

    1. TCHAR c = TEXT('A');
    2. TCHAR buffer[100] = TEXT("string");

    4.Windows中的Unicode函数和ANSI函数

    如果一个Windows函数的参数列表中有字符串,则通常有两个版本。例如:CreateFile

    1. WINBASEAPI
    2. HANDLE
    3. WINAPI
    4. CreateFileA(
    5. _In_ LPCSTR lpFileName,
    6. _In_ DWORD dwDesiredAccess,
    7. _In_ DWORD dwShareMode,
    8. _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    9. _In_ DWORD dwCreationDisposition,
    10. _In_ DWORD dwFlagsAndAttributes,
    11. _In_opt_ HANDLE hTemplateFile
    12. );
    13. WINBASEAPI
    14. HANDLE
    15. WINAPI
    16. CreateFileW(
    17. _In_ LPCWSTR lpFileName,
    18. _In_ DWORD dwDesiredAccess,
    19. _In_ DWORD dwShareMode,
    20. _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    21. _In_ DWORD dwCreationDisposition,
    22. _In_ DWORD dwFlagsAndAttributes,
    23. _In_opt_ HANDLE hTemplateFile
    24. );

    CreateFileA:接受ANSI字符串。

    CreateFileW:接受Unicode字符串。W代表wide

    返回字符串长度的函数:

    1. #ifdef UNICODE
    2. #define _tcslen wcslen
    3. #else
    4. #define _tcslen strlen
    5. #endif

    5.新的安全字符串函数

    现有的字符串处理函数如_tcscpy等已被标记位废弃不用。现在它们都对应了一个新版本的函数,前面名称相同,最后加了一个_s后缀。示例:

    1. TCHAR before[3] = { TEXT('A'),TEXT('B') ,'\0'};
    2. TCHAR after[3] = { TEXT('-'),TEXT('-') ,'\0'};
    3. errno_t result = _tcscpy_s(after, _countof(after), before);

    6.处理字符串的函数

    除了新的安全字符串函数,C运行库还新增了一些函数,用于在执行字符串处理时提供更多控制。自然,这些函数提供了ANSI(A)版本和Unicode(W)版本。

    1. StringCchCat(PTSTR pszDest, size_t cchDest, PTSTR pszSrc)
    2. StringCchCopy(PTSTR pszDest, size_t cchDest, PTSTR pszSrc)

    在这些方法中,都含有一个“Cch”,这表示Count of characters,即字符数;通常使用_countof来获取值。

    另外还有一系列的名称中含有“Cb”的函数,比如StringCbCat、StringCbCopy,这些函数要求用字节数来指定大小,通常使用sizeof来获取值。

    还有一些末尾加了Ex的函数,表示可扩展的版本,例如StringCchCatEx、StringCchCopyEx。

    7.推荐字符和字符串的处理方式

    最好将应用程序转换为支持Unicode的形式。

    • 用通用的数据类型(TCHAR/PTSTR)表示文本字符和字符串。
    • 用BYTE和PBYTE表示字节、字节指针和数据缓冲区。
    • 用TEXT或_T宏来表示字面常量字符和字符串。
    • 修改与字符串有关的计算。例如:我们需要知道缓冲区大小的字符数,而不是字节数,应该调用_countof(buffer),而不是sizeof(buffer)。
    • 执行全局替换。例如:用PTSTR替换PSTR。

    以下为使用Unicode的好处:

    • 有利于应用程序本地化。
    • 只需发布一个二进制文件,即可支持所有语言。
    • 提升应用程序效率,代码执行速度更快,占用内存更少。Windows内部的一切工作都是使用Unicode字符和字符串来进行的。如果使用ANSI字符和字符串,Windows就会被迫分配内存,将ANSI字符或字符串转为Unicode。
    • 应该程序能够调用所有尚未弃用的Windows函数,因为一些Windows函数只提供处理Unicode的字符和字符串。
    • 应用程序代码很容易与COM集成。
    • 应用程序代码很容易与.NET Framework集成。

    8.Unicode与ANSI字符串转换

    1. //将多字节的字符串转换为宽字符字符串
    2. MultiByteToWideChar(
    3. _In_ UINT CodePage,
    4. _In_ DWORD dwFlags,
    5. _In_NLS_string_(cbMultiByte) LPCCH lpMultiByteStr,
    6. _In_ int cbMultiByte,
    7. _Out_writes_to_opt_(cchWideChar,return) LPWSTR lpWideCharStr,
    8. _In_ int cchWideChar
    9. );
    10. //将宽字符字符串转换为多字节字符串
    11. WideCharToMultiByte(
    12. _In_ UINT CodePage,
    13. _In_ DWORD dwFlags,
    14. _In_NLS_string_(cchWideChar) LPCWCH lpWideCharStr,
    15. _In_ int cchWideChar,
    16. _Out_writes_bytes_to_opt_(cbMultiByte,return) LPSTR lpMultiByteStr,
    17. _In_ int cbMultiByte,
    18. _In_opt_ LPCCH lpDefaultChar,
    19. _Out_opt_ LPBOOL lpUsedDefaultChar
    20. );

  • 相关阅读:
    【Jetson Nano】jetson nano一些基本功能命令
    日语等级J.TEST的自测卷
    使用树莓派连接摄像头与实时视频
    电气成套设备行业如何借助ERP系统,解决企业管理难题?
    助力智慧化管理-PX30核心板赋能高频读卡器领域
    UE4基础必学系列:数据驱动
    java中的包
    Postman接口断言&上下游参数传递
    python学习: count()、find()、index()方法
    vue3.0 构建后管 test development production 环境 以及路由跳转正常点击刷新出现cannot get
  • 原文地址:https://blog.csdn.net/wzz953200463/article/details/126235634