c程序在cygwin、linux下输出乱码问题解决

最近在写一个小工具,跑在linux和windows下,因为没有界面,是后台处理,就直接在linux下开发了,windows下就在cygwin下编译,不需要做任何修改就可以正常工作。美中不足的是在cygwin下输出汉字会乱码。
    
    cygwin编译出来的代码可以在cygwin环境下运行,也可以脱离cygwin环境直接在windows下运行,这两种情况实际运行效果有些差异,在cygwin环境下正确设置环境变量LANG就不会乱码,然而相同的执行文件直接在windows下运行仍然会乱码,即使同样设置了环境变量LANG。
    
    没办法了,只能改用宽字符输出了,不过好处是顺便实现了自动适应运行环境gbk和utf8编码的问题。
    
    示例程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

int main (int argc, char *argv[])    {
    char s[]="中文测试abc123。";
    wchar_t ws[1000];
    setlocale(LC_ALL, "zh_CN.UTF-8");
    mbstowcs(ws,s,sizeof(ws));
    setlocale(LC_ALL,"");
    printf("%s\n",s);
    printf("%ls\n",ws);
    return 0;
}


    源程序使用gbk编码,在linux和cygwin下用以下命令编译:
    g++ -g -Wall -finput-charset=gbk -o xxx xxx.cpp
    
    编译结果在utf8环境下(LANG=zh_CN.UTF8)运行两行输出都不会乱码,在gbk环境下(LANG=zh_CN.GBK)第一行乱码第二行正常。这个运行结果在cygwin环境、windows环境、linux环境下均是相同的。
    
    注意printf格式%s和%ls的区别,%s表示后面的字符串是普通字符串,这样在输出时不做转换,原来是什么编码就输出什么编码,而%ls表示后面的是宽字符串,输出时会做转换,所以只要正确设置了LANG环境变量,就可以自动适应环境,输出正确的编码串。这就是为什么两行输出第二行不会乱码,第一行只有在指定环境(UTF8)下才不会乱码的原因。
    
    一旦使用宽字符输出,那么编译器就需要知道源程序是什么编码,这样才方便做转换,如果不设置,g++默认是utf8编码,因为这个源程序使用了gbk编码,所以在编译的时候要用-finput-charset=gbk通知编译器,如果源程序已经是utf8编码了,那就可以省掉这个选项或者改成utf8。
    
    还有个选项-fexec-charset,默认也是utf8,我们编译的时候没指定这个参数,所以编译出来的结果中字符串s已经是utf8的字符串了,这也是为什么在utf8环境下两行输出都不乱码的原因。我们可以在编译时加上-fexec-charset=gbk,这样字符串s就是gbk的编码,执行的时候就会在gbk环境下%s输出也不乱码,反而在utf8环境下%s乱码了。
    
    如果加上了-fexec-charset=gbk,那么setlocale(LC_ALL, "zh_CN.UTF-8")要改成setlocale(LC_ALL, "zh_CN.GBK"),因为mbstowcs受setlocale的影响,我们要转换的字符串s是编译期决定的,那么setlocale的设置必须和-fexec-charset的设置相同,mbstowcs的转换才是正确的。
    
    mbstowcs转换的时候,我们要根据需要转换的源字符串编码正确设置setlocale,而输出的时候就需要根据当前环境的设置调整locale,所以在输出前使用了setlocale(LC_ALL,""),""表示根据环境变量来设置。
    
    还要强调一点,据说g++不能混用wprintf和printf,既然printf同样可以输出宽字符串,那么我们就统一使用printf吧,看起来并不需要使用wprintf。
    
    最后总结一下吧:要想在复杂情况下尽可能减少乱码情况,就需要用%ls输出宽字符串,不要再使用%s了,%s无法根据具体环境自动转换。可以只在输出的时候把普通字符串转换成宽字符串输出,处理继续使用普通字符串。
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值