ref: https://www.cnblogs.com/gatsby123/p/11150472.html
Unicode
字符集
代码点
与编码表中的某个字符对应的代码值。在Unicode标准中,代码点采用十六进制书写,并加上前缀U+,例如U+0041就是A的代码点。
Unicdoe的代码点分为17个代码级别,第一个代码级别称为基本的多语言级别,代码点从U+0000 ~ U+FFFF,又称基本多文种平面(Basic Multilingual Plane, BMP),或称第零平面(Plane 0)。
其余的16个代码级别从U+10000 ~ U+10FFFF
utf-8
码点起值 | 码点终值 | 字节序列 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 |
---|---|---|---|---|---|---|---|---|
U+0000 | U+007F | 1 | 0xxxxxxx | |||||
U+0080 | U+07FF | 2 | 110xxxxx | 10xxxxxx | ||||
U+0800 | U+FFFF | 3 | 1110xxxx | 10xxxxxx | 10xxxxxx | |||
U+10000 | U+1FFFFF | 4 | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | ||
U+200000 | U+3FFFFFF | 5 | 111110xx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | |
U+4000000 | U+7FFFFFFF | 6 | 1111110x | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
第一个字节要么最高位是0(ASCII码),要么最高位都是1,最高位之后的1的个数决定了后面的有多少个字节也属于当前字符编码,例如111110xx,最高位之后还有4个1,表示后面的4个字节属于当前编码。后面的每个字节的最高位都是10,可以和第一个字节区分开来。后面字节的x表示的就是UCS编码。所以UTF-8就像一列火车,第一个字节是车头,包含了后面的哪几个字节也属于当前这列火车的信息,后面的字节是车厢,其中承载着UCS编码。
当前utf-8字节长度为1~4字节,对应代码点从U+0000 ~ U+10FFFF。
utf-16
Windows默认的Unicode编码的保存方案,就是UTF-16。
计算机中为何不直接使用 UTF-8 编码进行存储而要使用 Unicode 再转换成 UTF-8 ? - farta的回答 - 知乎
Unicode 编号范围(十六进制) | 具体的 Unicode 编号(二进制) | UTF-16 编码 | 编码后的字节数 |
---|---|---|---|
0000 0000 ~ 0000 FFFF | xxxxxxxx xxxxxxxx | xxxxxxxx xxxxxxxx | 2 |
0001 0000 ~ 0010 FFFF | yyyy yyyy yyxx xxxx xxxx | 110110yy yyyyyyyy 110111xx xxxxxxxx | 4 |
注:位于 D800~0xDFFF 之间的 Unicode 编码是特别为四字节的 UTF-16 编码预留的,在这个范围内没有收录任何字符,被称为替代区域。
utf-32
用4个字节表示一个字符
编译与源文件
gcc中跟编码方式转换有关的3个编译选项:
- -finput-charset=charset,指定源文件本身的编码方式,默认为UTF-8(有无BOM均可)。例如当我们的源代码文件保存为GBK时,则也应当将此选项的值指定为GBK。
- -fwide-exec-charset=charset,指定宽字符或宽字符串的字面值常量的内部编码方式,默认为UTF-32或UTF-16,对应wchar_t的宽度。wchar_t的宽度依赖平台实现,windows 实现为2字节宽,linux 实现为4字节宽。例如指定此选项为GBK,则宽字符或宽字符串常量将会以GBK编码方式存储,而不是默认的UTF-16或UTF-32编码方式。
- -fexec-charset=charset,指定窄字符或窄字符串的字面值常量的内部编码方式,默认为UTF-8。例如指定此选项为GBK,则窄字符或窄字符串常量将会以GBK编码方式存储而不是默认的UTF-8编码方式。
C++1x提供了更多字符串字面值表示法:
"string of char characters in some implementation defined encoding" - char
u8"string of utf8 chars" - char
u"string of utf16 chars" - char16_t
U"string of utf32 chars" - char32_t
L"string of wchar_t in some implementation defined encoding" - wchar_t
源代码中的字符串经过 finput-charset 解码,再以 fwide-exec-charset 或 f-exec-charset 编码,存储在编译后的目标文件中。
ref: Visual Studio相关:https://www.cnblogs.com/jiangxueqiao/archive/2017/09/01/7464408.html
当向终端、控制台输出 wchar_t 类型的字符时,需要设置 setlocale(),因为通常终端、控制台环境自身是不支持 UCS 系列的字符集编码的,使用流操作函数时(如:printf()),在标准/RT库实现的内部会将 UCS 字符转换成合适的本地 ANSI 编码字符,转换的依据就是 setlocale() 设定的活动 locale,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。
C标准库的setlocale()用法笔记
为什么printf可以打印中文,而wprintf却一定要setlocale才能正确打印?
Why printf() does not care of my locale settings ?