c和宽字符


#C 语言


2014-07-24

这是一年前的笔记。

操作系统默认字符集为utf-8。

示例1

例如:(文件编码为utf-8)

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t *s=L"你好";
    printf("%ls\n",s);
    printf("%S\n",s);
    printf("length:%ld\n",wcslen(s));
    printf("%C\n",s[0]);
    return 0;
}

编译输出:

你好
你好
length:2
你

示例2:

文件编码仍然为utf-8。

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.GB18030");
    wchar_t *s=L"你好";
    printf("%ls\n",s);
    printf("%S\n",s);
    printf("length:%ld\n",wcslen(s));
    printf("%C\n",s[0]);
    return 0;
}

编译运行:

���
���
length:2
�

宽字符转换为多字符

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t *s=L"你好";
    char ch[100];
    wcstombs(ch,s,100);
    printf("%s\n",ch);
    printf("length:%ld\n",strlen(ch));
    printf("%c\n",ch[0]);
    return 0;
}

编译运行:

你好
length:6

获取汉字的utf-8编码

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t s[]=L"你好";
    char ch[100];
    wcstombs(ch,s,100);
    printf("%s\n",ch);
    printf("%x %x %x %x %x %x\n",(int)ch[0],ch[1],ch[2],ch[3],ch[4],ch[5]);
    return 0;
}

编译运行结果为:

zsh >> gcc test.c
zsh >> ./a.out   
你好
ffffffe4 ffffffbd ffffffa0 ffffffe5 ffffffa5 ffffffbd

在python交互环境中获取"你好"的utf8编码用来验证:

>>> u"你好".encode("utf-8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> 

实际上下面这种方法也能获得(源文件是utf-8编码):

#include <stdio.h>
int main()
{
    char *s="你好";
    printf("%x %x %x %x %x %x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
    return 0;
}

多字符转换为宽字符

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t s[100];
    char *ch="你好";
    mbstowcs(s,ch,100);
    printf("%ls\n",s);
    printf("length:%ld\n",wcslen(s));
    printf("%C\n",s[0]);
    return 0;
}

编译运行:

zsh >> gcc test.c
zsh >> ./a.out   
你好
length:2
你

%ls%s的区别很简单,%ls意味着将对应的参数会被当作基于宽字符的字符串(wide chraracter string )看待,而%s则意味着对应的参数会被当作普通字符串(multi-byte string)看待。

wprintf

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t s[]=L"你好";
    wprintf(L"---%ls\n",s);
    //printf("%ls\n",s);
    wprintf(L"---%ls\n",s);
    return 0;
}

编译运行:

zsh >> gcc test.c
zsh >> ./a.out   
---你好
---你好

有趣的现象

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t s[]=L"你好";
    wprintf(L"---%ls\n",s);
    printf("%ls\n",s);
    wprintf(L"---%ls\n",s);
    return 0;
}

编译运行:

zsh >> gcc test.c
zsh >> ./a.out   
---你好
---你好

再来个:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
int main()
{
    setlocale(LC_ALL,"zh_CN.utf8");
    wchar_t s[]=L"你好";
    printf("%ls\n",s);
    wprintf(L"---%ls\n",s);
    printf("%ls\n",s);
    wprintf(L"---%ls\n",s);
    return 0;
}

编译运行:

zsh >> gcc test.c
zsh >> ./a.out   
你好
你好

还有其他的处理宽字符的函数,例如wsprintf,wscanf。



( 本文完 )