MFC 的宏太多了,让人目不暇接,回想 Linux 下的多简单呢,各种各样的接口和调用都都非常少,哪里像 MFC 这么恶心。

字符集(CharacterSet)与编码(Encoding)

我们先要区分开这两个概念才能理解后面文中说的那么多符号到底是什么东西。

  • 字符集。符号的集合。对于字符集的每个符号,用一个代码来表示,就叫编码。
  • 编码。对于符号的编码,我们需要存储在计算机中,这个就叫存储。

ANSI

ANSI 是一套字符集,其编码就是 ANSI 编码。

ASNI 中有 8bit 来存储一个字符,所以其支持的符号是有限的,只有最多 256 个,这对于我们中文来说肯定是不够的。

Unicode

Unicode 是一套字符集,其没有定义编码,所以说其有多种实现。也就是说对于 Unicode 有多种形式来存储在计算机上。

UTF-8

UTF-8 是 Unicode 的一个编码实现,其使用变长字节来存储 Unicode 编码。

UTF-8 的存储规则如下:

  • 单字节符号。第一位为 0,后面 7 位是其 Unicode 码,在英文字母中, ANSI 与 Unicode 编码一致。
  • N 字节的符号(N>1)。第 1 字节的前 n 位置 1,n+1 位置 0,后面所有字节的前两位都是 0。其余位就保存了 Unicode 编码。

UTF-8 中,中文字符需要三个字节来存储,英文字符只需要一个字节来存储。

UTF-16/UCS-2

固定使用 2byte 的 Unicode 编码。

UTF-32/UCS-4

固定使用 4byte 的 Unicode 编码。

MFC 中的应用

char wchar_t

char 是 8bit 的,其只能表示应该 ANSI 字符。
wchar_t 表示一个宽字符类型,意思是多字节的,可以存储任何 Unicode 字符,因此我们在涉及中文的时候一般都会用到。

MFC 中一般不直接使用这两个类型,而是使用很多定义了的宏。

L

这个很简单,这个一般用来放在字符前面,告诉编译器,这是一个 Unicode 字符。

_T _TEXT

其定义为:

#define _T(x)       __T(x)
#define _TEXT(x) __T(x)

而根据我们程序使用字符集的不同,__T 有两种定义形式:

#define __T(x)      L ## x // Unicode

#define __T(x) x //ANSI

所以说,_T 会根据我们程序的字符集类型来自动匹配字符的编码。

TEXT

_TEXT 定义在 winnt.h 中,其作用与 _T 一致。

使用

我们在用到字符的时候,必须告诉编译器,我们的字符是什么类型的,以此才能决定如何存储在文件中去。

因此我们可以使用 _T, _TEXT, TEXT

CString

CString, CStringA, CStringW 都是模板类 CStringT 的一个特殊实现。不同在于:

  • CStringW 包含了 wchar_t 类型,支持 Unicode 字符。
  • CStringA 包含了 char 类型,支持单字节和多字节字符。
  • CString 根据编译时指定的字符类型决定其应该是什么类型。Unicode 和单字节多字节都支持。

CString 对象支持将字符存在在一个 CStringData 对象内,其接受 C 风格的 NULL 结尾的字符串。CString 可以更高性能的跟踪字符串的长度,但它也支持从存储的字符数据内获取 NULL 字符来支持转换到 LPCWSTR 类型。

有几种类型不需要链接到 MFC 库就能使用:CAtlString[AW]。

构造一个 CString:

#include <atlstr.h>

int main() {
CString aCString = CString(_T("A string"));
_tprintf(_T("%s"), (LPCTSTR) aCString);
}