C++ Windows编程中的一些编码处理
本文最后更新于 123 天前,其中的信息可能已经有所发展或是发生改变。

前言

阅读前,已默认读者已经熟知编码,ASCII,字符集等与编码相关的概念,前言中也会对这些概念进行粗略的讲解,若看不懂,可以先去学习相关概念,再来阅读本篇文章。

由于web的普及,各国家之间的信息交换成为可能,然而不同国家对其文字定义的字符集并不相同,这也间接促成了Unicode的诞生。

什么是字符集呢?可以理解成字符数字(数码)之间的映射集,为了方便,接下来的数字(数码)我都使用16进制进行表示。

比如"中"这个字在GBK字符集中就对应着d6d0这个数字,而在UNICODE字符集中则对应着4e2d这个数字。

但是,单单有字符集并没有完全解决与信息交换以及存储相关的问题,例如,如何将字符集中的字符进行编码并用于计算机间的交换储存,就是个问题。

举个实际例子吧,已知“中国NO.1”的UNICODE码4e2d 56fd 004e 004f 002e 0031,若简单的直接依照这个十六进制字符串对其进行保存,那么字符串中英文字符的占用空间将会是ASCII码的两倍!这也太浪费了。

然后,UTF8,一个UNICODE字符集的可变长编码方案诞生了。这里就不展开讨论UTF8的编码原理了,而是直接阐述windows编程中的相关处理办法。

解决方案

UTF8 -> UTF16

由于UTF8的可变长特性,在计算机中我们一般使用bytechar序列来储存U8字符串,在C++中,char序列可以用string代替。可能有疑惑会什么不能用wstring,因为wstring的基本单位是两字节长度的wchar_t,而对于使用UTF8编码后编码长度为三字节的汉字来说,这就可能导致存储相关的问题(字节无法对齐了)。

但这里有个问题啊,windows操作系统默认使用UNICODEUTF16编码,若在控制台直接输出UTF8字符串,可能得到以下结果

#include <iostream>
using namespace std;

int main()
{
    system("title CODEPAGE TEST");
    unsigned char str[] = { 0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD, 0x4E, 0x4F, 0x2E, 0x31, 0x0 };
    string s = (char*)str;
    printf("%s\n", s.c_str());
    system("pause");
    return 0;
}
 涓�鍥絅O.1
​VS2022运行结果​
​MINGW-W64运行结果​

所以我们需要对UTF8编码的string进行转换,转换成UTF16wstring后再输出就可以正常显示了了

#include <iostream>
#include <locale>         // std::wstring_convert
#include <codecvt>        // std::codecvt_utf8
using namespace std;
std::wstring UTF8ToUnicode(const std::string& str)
{
	std::wstring ret;
	try {
		std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
		ret = wcv.from_bytes(str);
	}
	catch (const std::exception& e) {
		std::cerr << e.what() << std::endl;
	}
	return ret;
}

int main()
{
	system("title CODEPAGE TEST");
	unsigned char str[] = { 0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD, 0x4E, 0x4F, 0x2E, 0x31, 0x0 };
	string s = (char*)str;
	wstring wstr = UTF8ToUnicode(s);
	setlocale(LC_CTYPE, "");
	printf("%ls\n", wstr.c_str());
	system("pause");
	return 0;
}
VS2022运行结果​

MINGW-W64运行结果​

由于vs编译生成的字符串默认使用ANSI(中文电脑上是GBK),而MINGW-W64默认使用UTF8,因此俩输出结果可能有差异。

不过观察十六进制输出可以发现,两者除了字节序有差异外,都成功的转换成了UTF16编码的wstring

UNICODE <-> ANSI

其实在Windows中,string默认的编码是ANSI,中文电脑上ANSI其实是GBK

那么UTF16编码的wstring如何和ANSI(GBK)编码的string进行转换呢?WindowsAPI提供了两个函数WideCharToMultiByteMultiByteToWideChar。函数名称中的WideChar代表UTF16编码的字符串,而MultiByte代表ANSI编码的字符串

具体实现可以参照以下代码

因为要用到winAPI,所以需要引用windows.h

std::wstring CharToWchar(string s, size_t m_encode = CP_ACP)
{
	std::wstring ret;
	const char* c = s.c_str();
	int len = MultiByteToWideChar(m_encode, 0, c, strlen(c), NULL, 0);
	wchar_t* m_wchar = new wchar_t[len + 1];
	MultiByteToWideChar(m_encode, 0, c, strlen(c), m_wchar, len);
	m_wchar[len] = '\0';
	ret = m_wchar;
	delete[] m_wchar;
	return ret;
}
std::string WcharToChar(wstring ws, size_t m_encode= CP_ACP)
{
	std::string ret;
	const wchar_t* wp = ws.c_str();
	int len = WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), NULL, 0, NULL, NULL);
	char* m_char = new char[len + 1];
	WideCharToMultiByte(m_encode, 0, wp, wcslen(wp), m_char, len, NULL, NULL);
	m_char[len] = '\0';
	ret = m_char;
	delete[] m_char;
	return ret;
}

参考

C++中字符编码的转换(Unicode、UTF-8、ANSI)FlushHip-CSDN博客c++ utf8

评论

  1. 第儿
    Windows Edge 99.0.1150.52
    1月前
    2022-4-06 12:50:42

    好厉害鸭

  2. jtry
    Android Chrome 86.0.4240.99
    2月前
    2022-3-26 13:55:58

    厉害👍🏻

  3. Styunlen 博主
    Android Chrome 89.0.4389.72
    4月前
    2022-1-16 13:14:09

    写这篇博文的起因是一位群友提了一个wstring为什么无法正确输出的问题

    • 第儿
      Windows Edge 99.0.1150.52
      1月前
      2022-4-06 12:51:33

      你在手机上用chrome?

      • Styunlen 博主
        Android Chrome 66.0.3359.126
        2周前
        2022-5-04 8:10:36

        其实是手机版的Edge啦

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
Source: https://github.com/zhaoolee/ChineseBQB
Source: https://github.com/zhaoolee/ChineseBQB
Source: https://github.com/zhaoolee/ChineseBQB
颜文字
Emoji
小恐龙
花!
滑稽大佬
演奏
程序员专属
上一篇
下一篇