C 语言默认的 char 类型是单字节字符,仅支持 ASCII 码。但是 ISO C90 标准开始,定义了 wchar_t 类型用于支持多字节字符(头文件 wchar.h)。
这一版标准中还定义了本地化和国际化相关的头文件 locale.h,可以通过其中的 setlocale 函数设置使用的字符集编码,一般用 UTF-8 足够了。

每一种语言都分为内部编码(程序代码中使用的)和外部编码(例如打开的文件,接受的网络数据)。

要写 C 代码,最小的字符集就是 ASCII 码,也就是 C 程序初始化时默认的编码。此时 locale 设置成 C。如果需要输出多字节字符,可以在 main 函数中修改编码方式。

宽字节字符串有一系列单独的处理函数,通常以 wcs (wide character sequence 宽字符序列)开头,例如 wcslen()wcscmp() 等。注意不要混用单字节字符处理函数和多字节字符处理函数,例如 printf 和 wprintf。对于多字节字符,在用 wprintf 输出时,lc 表示宽字节字符,ls 表示宽字节字符串。

操作系统也有本地化设置的相关参数,例如对于 Linux 可以用 locale 命令查看。其中 LANG 会设置到环境变量中,这个需要跟 C 语言中设置的编码一致(对于下面的编码,C 语言中可以设置为 C.UTF-8):

$ locale
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=zh_CN.UTF-8
LC_TIME=zh_CN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=zh_CN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
LC_TELEPHONE=zh_CN.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
LC_IDENTIFICATION=zh_CN.UTF-8
LC_ALL=
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void) {
    setlocale(LC_ALL, "C.UTF-8"); 	// 设置字符集,必须与本机编码后缀一致,例如 en_US.UTF-8
    wchar_t* s = L"你好";			// 字符串前加 L 转为宽字节字符串
    wprintf(L"你好c test %S", s);	// wprintf 函数中,格式字符串也必须是宽字节的
//    printf("你好c test %S", s);		// 这里有时也可以正常输出,但可能导致异常
//    printf("你好c test %ls", s);

    return 0;
}

获取输入流的 UTF-8 数据

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main() {
	setlocale(LC_ALL, "C.UTF-8");
	wchar_t c;
	wscanf(L"%lc", &c);
	wprintf(L"%lc\n", c);
//	printf("换人"); 		// 还是不用混用 printf wprintf
	return 0;
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐