char,wchar_t,charxx_t
引言:
C语言中,字符型(char)数据类型存储字符(character),其保证了单个char所占用的资源空间的大小为该存储系统所能使用的基本字符集的最小大小;C语言定义一个字节(byte)的位数为char的位数:
$$
Char:1~byte \
1~byte =8~bit
$$
字符型变量其实存储的是整型常量,可以进行相应的数学运算和比较操作.
$$
unsigned~char \in \left [ 0,256\right ] \
signed~char \in \left [ -128,127\right ]
$$
在不同的编译器和平台上,char类型的默认符号性可能会有所不同,最好使用明确的声明如:
signed char s_char;
unsigned char u_char;
C语言的字符串是由多个字符组成的序列,以空字符('\0')作为结束符:
char str[] = "Hello World!"; //若如此使用,编译器会自动在最后添加\0结束符
对字符的输出输入:printf(),scanf(),同时可以使用具有运行约束的printf_s和更安全的scanf_s.
char类型处理字符串信息方面提供了处理函数,本质是对字符数组进行处理,以下列出部分:
strcpy() //复制字符串到另一个字符串
strcat() //将字符串连接到另一个字符串末尾
strlen() //获取字符数组的长度
strcmp() //比较两个字符数组是否相等
类型转换,参考ASCII表格,这里不再赘述,例子:
char a = 48;//a == '0'
char b = 65;//b == 'A'
char c = 97;//c == 'a'
wchar_t
引入的原因:char为1字节(8位)字符类型,最多包含256种字符,许多国际语言如中文字符数超出了256个,char无法正确表示.C/C++中引入wchar_t,一种扩展字符的存储方式,其数据类型一般为2字节(16位)或4字节(32位),在不同的规范中有可能不同;其所带来的结果就是能用wchar_t表示更多的字符数.标准C++中wprintf及iostream类库中的类和对象能提供对此类型的相关操作.
setlocale(LC_ALL,"zn_CN.UTF-8"); //locale.h,针对中文国际化,允许输出wchar_t字符
wchar_t wStr[] = L"你好,世界!"; //前缀 L 用来指示宽字符常量和宽字符串
std::wcout << wStr << std::endl;
注意,char和wchar_t的流对象不能混用,否则会导致无法使用的异常,同时cout,wcout并没有printf,wprintf好用,至少后者都可以输出wchar_t字符,可以选择重载cout的 operator<<;同时,因为wchar_t的定义方式,此类型与另一种整型underlying的长度和符号属性相同,对底层类型的选择取决于实现,因此,在不同的系统环境中,其可能是unsigned short或者int等.
宽字符处理函数及与普通函数对照区别:
size_t __cdel wchlen(const wchar_t*);
ANSI下字符串以'\0'作为结束符,而Unicode以"\0\0"作为结束符,如若用strlen对wchar_t*进行操作,则可能会出现长度返回为1~(真实长度 * 2)的结果,因为其按照1字节的读法下,某一个Unicode宽字符的后两位可能为00(即'\0'结束符).
以下列举一些针对宽字符的处理函数:
iswalnum() //<-> isalnum 测试是否为数字或字母
iswalpha() //<-> isalpha 测试字符是否为字母
iswcntrl() //<-> iscntrl 测试字符是否为控制符
//...
towlower() //<-> tolower 把字符转换为小写
towupper() //<-> toupper 把字符转换为大写
//...
fgetwc() //<-> fgetc 从流中读入一个字符并转换为宽字符
fgetws() //<-> fgets 从流中读入一个字符串并转换为宽字符串
getwc() //<-> getc 从标准输入中读取字符,并且转换为宽字符
//...
wcscat() //<-> strcat 把一个字符串接到另一个字符串尾部
wcscpy() //<-> strcpy 拷贝字符串
wcslen() //<-> strlen 获取宽字符串长度
//对应memory的wmemcpy().wmemchr(),wmemcmp(),wmemmove(),wmemset();
wchar_t与char转换:
方法一:
使用 atlconv.h 中包含的Windows宏 W2A,A2W,
每次使用前需使用 USES_CONVERSION:
wchar_t wc[] = L"我是宽字符";
USES_CONVERSION;
char *c = W2A(wc);
方法二:
使用Windows的ATL里的类CW2A和CA2W,第二参数可以控制编码,不加则为保持编码
需要头文件 atlbase.h 或 atlstr.h,笔者IDE无法顺利转换
方法三:
调用 Window API 中的WideCharToMultiByte 和 MultiByteToWideChar
参考方法:
std::wstring CharToWchar(const char* c, size_t m_encode = CP_ACP)
{
std::wstring 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';
str = m_wchar;
delete m_wchar;
return str;
}
std::string WcharToChar(const wchar_t* wp, size_t m_encode = CP_ACP)
{
std::string 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';
str = m_char;
delete m_char;
return str;
}
方法四:
使用C的mbstowcs方法和wcstombs方法,且配合setlocale方法,但需要额外转码,不推荐在windows平台上使用.
char16_t 和 char32_t
char16_t用于存储以UTF-16编码的Unicode字符,是16位宽字符类型
char32_t用于存储以UTF-32编码的Unicode字符,是32位宽字符类型
char8_t,char16_t,char32_t的大小和表示方式在c++标准中是固定的,不依赖于平台和编译器;他们更适合于编写跨平台代码并希望保持一致的字符大小和表示方式;如果只关心本地编码(ASCII),并且不关心Unicode支持,char已经足够.
其字符数组与字符串类型对应关系为:
char16_t * == std::u16string;
char32_t * == std::u32string;
wchar_t * == std::wstring;
//c++ 20 standard
char8_t == std::u8string;
basic_string
basic_string是一个模板类,并且是容器模板类,其对象管理的序列是标准的C++字符串,包括string,wstring,u16string,u32string.
typedef std::basic_string<char> string;
typedef std::basic_string<wchar_t> wstring;
typedef std::basic_string<char16_t> u16string;
typedef std::basic_string<char32_t> u32string;