C99 宽字符
1 前言
这两天学习 C99标准
的过程中, 宽字符的问题可是花了我不少时间。
趁现在印象还比较深,总结下来。
2 头文件
<wchar.h> – 对宽字符的支持是源自
C99标准
(准确来说应该是C95
) 的标准库<wchar.h>
这个头文件定义了宽字符类型:
wchar_t
(准确来说这个是源自C++的关键字, wchar.h 定义的类型应该是wint_t
, 但两者可以替换)- <locale.h> – 本地化支持设置
3 宽字符及本地化支持
一段简单的代码:
#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <wchar.h> int main(int argc, char* argv[]) { setlocale(LC_ALL, ""); // 本地化设置 char* str = "宽字符测试"; wchar_t* wstr = L"宽字符测试"; printf("%s\n", str); // 输出单(多)字节字符串 wprintf(L"%ls\n", wstr); // 输出宽字符串 getchar(); return 0; }
这段代码用于向控制台分别输出 多字节字符串
和 宽字符字符串
形式的 "宽字符测试"
.
其中,虽然多字节字符串形式的输出能够正常输出,但是这时你并不能对这个字符串进行操作,不然可能会出现乱码。
之所以能够正确输出相应的内容, 是因为 控制台
对字符串的原始字节序列进行了处理。如果这时对这个字符串进行操作,那么便会打乱原始字节序列,从而得不到想要得到的输出。
因此,为了能够对 非ASCII字符串
进行各种操作,我们需要用到宽字符。
3.1 本地化支持
在使用宽字符之前,我们需要了解一些相关的内容。
在不同的系统,平台,区域环境下,可能具有不同的区域设置,如: 编码格式 ,日期写法,文字排序等,为了保证程序能够输出正确的字符,便需要进行本地化支持。
在C语言中, 本地化支持需要用到到一个标准库头文件: <locale.h>
该头文件文件定义了一个函数: setlocale(int category, const char* locale)
这个函数用于将程序调整到特定的区域设置,而这个设置会影响到如: 字符串处理函数 的执行,如果没做好本地化支持,便可能会导致输出的字符串乱码。
其中: 参数 category
通过指定预定义的宏: LC_ALL、LC_COLLATE、LC_CTYPE、
LC_MESSAGES、LC_MONETARY、LC_NUMERIC、LC_TIME
来指定本地化设置的分类,其中: LC_ALL
是其他分类的并集。
而参数 locale
指定本次设置的内容,由于 windows
和 unix
系统的区别,所以设置的格式也有一定的区别,如果想要详细了解,可以查看以下文档:
- windows: windows setlocale
- unix: GNU Locales and Internationalization
- wiki: locale.h
如果没有显式的对本地化进行设置的话, C程序在运行前会 默认 运行 setlocale(LC_ALL, "C")
来进行本地化设置,而这个 C 对应着怎样的设置我们并不清楚,但是有一点,这个设置不适合 中文字符
的环境。
所以可以通过像这样 setlocale(LC_ALL, "")
来简单调用该函数,这时C程序会通过环境变量来进行本地化设置。简单省事。
注意: 这样的设置是系统默认的环境配置,可能和你程序需要的运行环境存在差异 !
3.2 文件编码格式设置
完成了本地化支持的设置,那么还有一个关键内容便是 文件编码格式
了。
首先要清楚的一个概念是: 程序并不知道你的字符串的编码是怎样的 !
除了 ASCII字符
在各个编码环境下对应的字节序列都是一样的外,其他字符的编码在各个环境的字节序列很有可能是不一样的。
程序并 不能自动识别
你定义的字符串的编码格式,它只会按照你指定的或按照默认的编码格式来读取处理相应的字节序列。
这时文件编码格式便会影响到 非ASCII码
字符的字节序列,如果文件编码格式与指定的环境的编码格式不一样,那么输出便可能乱码,或者出现 编译警告甚至错误 。
当然,这个问题如果是在用 VS 作为编译环境,那么应该不会发生 -_-
如果你遇到了问题,那么很有可能和我一样在 windows
上用 MinGW
编译程序。
Mingw
文件的默认读取和输出格式都是 UTF-8
, 而 windows
的默认编码格式是 GBK.
所以。。。
这就很难受。。。。。
这时你可以选择通过设置编译参数来修改编译时源文件的读取及输出格式。
- 参数:
-finput-charset=charset
设置源文件的读取格式, 根据你源文件的编码格式来。 - 参数:
-fexec-charset=charset
设置输出格式, windows 设置成GBK
就好了。
3.3 代码编写
前面两个步骤完成了基础设置, 这时候便需要了解一些在编程过程中需要注意的一些问题了。
- 定义宽字符字符串的时候应该在前面加上
L
- 格式化输出时应该用
%ls
而不是%s
, 格式化字符串前面也应该加上L
4 相关链接
- 维基百科:
- 个人博客
- 独立网页