上一篇文章介绍了char字符串有关的一些操作,strlen接口的实际含义,以及“一个中文占两个字节”的真实含义。
char的最初设计只是为了满足英文的需求,计算机普及后各个国家和地区开始针对本地的语言进行字符编码设计,中文也是其中之一。显而易见,一个字节(char)是无法满足这些编码需求的,于是不同语言的规定一个本地字符所占字节数不定,“多字节字符集”就是这么来的。含义就是多个字节表示一个字符,一个字符可能对应一个字节,也可能对应2个甚至更多的字节。
这种处理多字节很多时候对程序而言并不友好,随着硬件的快速发展,内存不再是计算机和程序的主要制约因素,于是很多高级编程语言就想,不管什么字符,全部用两个字节表示,那就可以大大提高程序(或者操作系统)对字符的处理能力。
C++语言自然也紧随潮流,设计了wchat_t字符,即宽字符,它不管具体字符是什么,全部按照两个字节来编码。为了和传统的char字符区分,wchar_t字符(串)在申明的时候,需要加上大写字母“L”。既然有wchar_t,标准库自然有其对应的字符串:wstring。
除此之外,还要注意,想要用标准输入输出流打印宽字节字符(串),不能用std::cout,需要用std::wcout;同样,如果是文件流,不能用fstream,需要用wfstream。
请看下面代码(vs2019,):
#include <iostream>
#include <string>
int main()
{
using namespace std;
const wchar_t* pwValue = L"I Love C++";
wstring strValue = pwValue;
cout << wcslen(pwValue) << endl;
cout << strValue.size() << endl;
cout << pwValue << endl;
wcout << pwValue << endl;
system("pause");
return 0;
}
执行结果如下:
是不是有些意外?逐行分析:
先定了一个const whcar_t*的字符串,将其作为参数构造一个wstring的字符串,这两行没问。
cout << wcslen(pwValue) << endl; ,打印pwValue中的字符数。这里有两点需要注意:
(1)char*字符串,用strlen接口;wchar_t*字符串,需要用wcslen接口;
(2)strlen计算是char*字符串中的字节数,而wcslen计算的是wchar_t*字符串中字符个数。
cout << strValue.size() << endl; 这句比较好理解,打印的是wstring字符串的字符个数。
cout << pwValue << endl;的结束很让人困惑,其实也很好理解:宽字节字符串,调用cout,打印的其实是第一个字符的地址;
wcout << pwValue << endl;这句打印字符串内容,很好理解。
但是!如果将字符串换成中文呢?调用wcout直接打印,会是什么结果?
请看下面代码(vs2019):
#include <iostream>
int main()
{
using namespace std;
const wchar_t* pwValue_en = L"I Love C++";
const wchar_t* pwValue_zh = L"Yes!我也爱C++";
wcout << pwValue_en << endl;
wcout << pwValue_zh << endl;
system("pause");
return 0;
}
执行结果如下:
什么情况?从“我”字符开始,之后的所有内容全部没有输出。
这里,涉及到C++的区域化问题,另一篇文章中有详细介绍。
想要输出宽字节的中文字符,需要设置一个区域,最好的办法是用C++的locale,当然也可以用c语言的setlocale,但不推荐。
修改后的代码如下:
#include <iostream>
int main()
{
using namespace std;
const wchar_t* pwValue_en = L"I Love C++";
const wchar_t* pwValue_zh = L"Yes!我也爱C++";
wcout.imbue(locale("zh_CN")); //设置语言环境
wcout << pwValue_en << endl;
wcout << pwValue_zh << endl;
system("pause");
return 0;
}
执行结果如下:
除此之外,还有关于char*和wchar_t*的相互转换问题,将会在另一篇文章中介绍。