TimothyQiu's Blog

keep it simple stupid

mbstowcs 与 wcstombs

分类:技术

还记得大明湖畔的 mbstowcswcstombs 吗?个人觉得这哥俩的存在感真的是比 setjmplongjmp 还要低啊。

size_t mbstowcs (wchar_t *dest, char const *src, size_t max);
size_t wcstombs (char *dest, wchar_t const *src, size_t max);

解释一下:「mbs」对应「Multibyte String」而「wcs」对应「Wide-character String」。于是顾名思义,这两位的功能就是把多字节字符串和宽字符字符串互相转换。

如果把 Wide-character 看作是 Unicode 的 code point,那么 Multibyte 就是对该 code point 的具体编码。至于这两个函数是如何得知 Multibyte 究竟使用什么编码,答案是他们根据当前 locale 中所指定的字符编码决定。下面的代码是在 Windows 上将 Big5 编码的字符串转换为 GBK 编码:

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

#define BUFFER_SIZE (128)

int main()
{
    char const *source = "Hello 世界!"; // 将文件保存为 Big5 编码

    wchar_t wc_out[BUFFER_SIZE];
    char    mb_out[BUFFER_SIZE];

    printf("%s\n", source);     // 输出不正常

    setlocale(LC_CTYPE, "chinese-traditional"); // 认为输入的 MBS是 Big5 编码
    mbstowcs(wc_out, source, BUFFER_SIZE);

    setlocale(LC_CTYPE, "chinese-simplified");  // 设置输出的 MBS 为 GBK 编码
    wcstombs(mb_out, wc_out, BUFFER_SIZE);

    printf("%s\n", mb_out);     // 正常输出

    return 0;
}

也可以试试日文 Shift-JIS 编码和 GBK 的转换:将文件存为 Shift-JIS 编码,然后把第一个 setlocale 的目标修改为 "japanese"(反正「世界」在简繁日里写法都一样)。甚至还可以跑到 Linux 上在「zh_CN.gbk」和 「zh_CN.utf-8」互转。

于是第一次知道这对函数时,我的第一想法是「哇,原来标准库里也有这样的函数啊!那我岂不是可以用很 portable 的方法来转换编码了?」无奈正常人都会说:你太甜了,这两个函数完全不可靠,还是用 Windows API 吧~还是用 libiconv 吧~

为什么呢?因为这两个函数所能进行的转换取决于 locale 的支持。例如 Windows 的中文 locale 就只能设置为 GBK 和 Big5 编码两种,Unix 的可用 locale 也和系统本身有关(?)。所以,想要通用还是老老实实用 libiconv 吧少年们~

参考:Code Pages Supported by Windows

Windows编码

添加新评论 »