- 应用程序应始终使用Unicode字符串,并且通过安全的字符串函数去操作字符串,防止缓冲区溢出错误
- Windows Vista中,每个Unicode字符都使用UTF-16编码
const wchar_t* pWStrC = L"Hello 蛮大人"; //字符串之前的L表示Unicode字符串
auto nSize = _tcsclen(pWStrC); //nSize = 9
/*
TCHAR, TEXT, _T, _tcs*系列函数可以根据是否定义UNICODE来生成或
处理ANSI或UNICODE字符串*
*/
#ifdef UNICODE
typedef wstring mstring;
#else
typedef string mstring;
#endif
//则mstring能很好的搭配TCHAR*使用
- 一些建议
- 始终用通用数据类型(TCHAR)来表示文本和字符串
- 用明确的数据类型(unsigned char)来表示字节、字节指针、数据缓冲区
- 用TEXT或_T表示字面量字符和字符串
- 始终使用安全的字符串处理函数
字符编码
ASCII
ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。
- 标准ASCII 码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。
- 后128个称为扩展ASCII码。
ANSI
不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、Big5、Shift_JIS 等各自的编码标准。这些使用 1 至 4 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 当然对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表1个字符。这一点是ANSI编码与Unicode编码之间最大也最明显的区别。
GB2312
GB2312 是对 ASCII 的中文扩展。
0-127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。
GBK
GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 加了几千个新的少数民族的字,GBK扩成了 GB18030。
UNICODE
- Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。目前的Unicode字符分为17组编排,0X00 至 0x10FFFF,每组称为平面(Plane),而每平面拥有65536个码位,共1114112个。然而目前只用了少数平面。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
- UTF-8
特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。
UNICODE | UTF-8 |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
- UTF-16
UNICODE编码0x00-0xFFFF之间的编码就用2个字节表示,0x010000-0x10FFFF部分的编码由4个字节表示(映射关系不研究),
Windows API 的 Wide Char 表达是 UTF-16
https://msdn.microsoft.com/en-us/library/windows/desktop/dd374081(v=vs.85).aspx- UTF-32
以32位无符号整数为单位。UNICODE的UTF-32编码就是其对应的32位无符号整数。
字符串转码与落盘
#include <string>
#include <assert.h>
#include <memory>
#include <Windows.h>
using std::unique_ptr;
template<typename T>
void Write(const char* pFilePathC, T* pStr, const size_t nSizeC, const
unsigned char* pAddFrontC = nullptr, const int nAddLenC = 0)
{
FILE* fp = _fsopen(pFilePathC, "wb", _SH_DENYWR);
if (fp)
{
size_t nRealSize = 0;
if (pAddFrontC)
{
nRealSize = fwrite(pAddFrontC, 1, nAddLenC, fp);
assert(nAddLenC == nRealSize);
}
nRealSize = fwrite(pStr, 1, nSizeC, fp);
assert(nSizeC == nRealSize);
fclose(fp);
return;
}
assert(false);
}
const bool ANSIToUTF8(const char* pStrInC, char* pStrOut,
const int nBuffLenC);
int main()
{
const char* pStrC = "Hello 蛮大人";
//内存中值(0x, 小端):48 65 6c 6c 6f 20 c2 f9 b4 f3 c8 cb 00
const wchar_t* pWStrC = L"Hello 蛮大人";
/*
内存中值(0x, 小端):
48 00 65 00 6c 00 6c 00 6f 00 20 00 ee 86 27 59 ba 4e 00 00
*/
unique_ptr<wchar_t[]> pWBuff(new wchar_t[wcslen(pWStrC) + 1]());
if (pWBuff)
{
for (size_t i = 0; i < wcslen(pWStrC); ++i)
{
pWBuff[i] = _byteswap_ushort(pWStrC[i]);
}
}
char aUtf8Str[1024] = {};
bool nRe = ANSIToUTF8(pStrC, aUtf8Str, sizeof aUtf8Str);
assert(nRe);
Write("ANSI.txt", pStrC, strlen(pStrC));
Write("UNICODE_NotAddHead.txt", pWStrC, wcslen(pWStrC) *
sizeof(wchar_t));
Write("UNICODE_BIG_NotAddHead.txt", pWBuff.get(), wcslen(pWStrC) *
sizeof(wchar_t));
Write("UTF-8_NotAddHead.txt", aUtf8Str, strlen(aUtf8Str));
const unsigned char aUnicode[2] = {0xFF, 0xFE};
const unsigned char aUnicodeBig[2] = {0xFE, 0xFF};
const unsigned char aUtf8[3] = {0xEF, 0xBB, 0xBF};
Write("UNICODE_AddHead.txt", pWStrC, wcslen(pWStrC) * sizeof(wchar_t),
aUnicode, 2);
Write("UNICODE_BIG_AddHead.txt", pWBuff.get(), wcslen(pWStrC) *
sizeof(wchar_t), aUnicodeBig, 2);
Write("UTF-8_AddHead.txt", aUtf8Str, strlen(aUtf8Str), aUtf8, 3);
/*
Windows的记事本对不同编码文件添加的数据头:
ANSI 无
UNICODE 0xFFFE
UNICODE-big 0xFEFF
UTF-8 0xEFBBBF
*/
/*
文件名 记事本 NotePad++
ANSI.txt 正常 正常
UNICODE_NotAddHead.txt 乱码 正常
UNICODE_AddHead.txt 正常 正常
UNICODE_BIG_NotAddHead.txt 乱码 乱码
UNICODE_BIG_AddHead.txt 正常 正常
UTF-8_NotAddHead.txt 正常 正常
UTF-8_AddHead.txt 正常 正常
*/
/*
#define CP_ACP 0 // default to ANSI code page
#define CP_OEMCP 1 // default to OEM code page
#define CP_MACCP 2 // default to MAC code page
#define CP_THREAD_ACP 3 // current thread's ANSI code page
#define CP_SYMBOL 42 // SYMBOL translations
#define CP_UTF7 65000 // UTF-7 translation
#define CP_UTF8 65001 // UTF-8 translation
*/
return 0;
}
const bool ANSIToUTF8(const char* pStrInC, char* pStrOut,
const int nBuffLenC)
{
int nSize = MultiByteToWideChar(CP_ACP, 0, pStrInC, -1, NULL, 0);
unique_ptr<wchar_t> pWBuff(new wchar_t[nSize]);
MultiByteToWideChar(CP_ACP, 0, pStrInC, -1, pWBuff.get(), nSize);
nSize = WideCharToMultiByte(CP_UTF8, 0, pWBuff.get(), -1, NULL, 0,
NULL, NULL);
if (nBuffLenC < nSize)
{
return false;
}
WideCharToMultiByte(CP_UTF8, 0, pWBuff.get(), -1, pStrOut, nSize,
NULL, NULL);
return true;
}