• windows程序设计01_utf8编码问题


    坚持与妥协

    从学程序的第一天老师就给我们说源代码应该使用utf8保存.因为先入为主,"源代码应该使用utf8"的观念已经在"学院派"出身的程序员脑子里根深蒂固.如果您固执地坚持自己的信仰,坚信源代码应该并且只应该用utf8保存,决不向任何工具或者人妥协!那么恭喜您,可以看看这个文章.

    VS2013及以前

    utf8是unicode的一种实现方式.windows95及以前,还没有unicode,更没有utf8.所以在windows95及以前微软自己定义了一套解决多国语言的规则(mbcs),因为windows95的巨大成功,大量程序都是用的微软自己定义国语言规则.到windows nt的时候unicode已经出现,所以的windows nt的内核用了unicode编码(UCS-2),内核彻底解决了多国语言.但是为了和已有代码兼容,windows 没有把自己的mbcs废除.mbcs用到什么时候?现在还在用.到VS2017,mbcs还是微软解决的多国语音问题的默认方式.在VS2013的时候,微软建议过不要再使用mbcs(参考资料5),以后的版本可能不再提供.但用户不干了,因为太多的程序是用mbcs的方式,修改成 unicode成本太大.所以到VS2015,mbcs又回来了,并且宣布以后的版本继续支持mbcs.微软那个纠结呀.

    VS2015,VS2017

    VS2013及以前微软的编译器cl只能支持utf8 with bom(或者是用mbcs的方式,中文用cp936),一直到到vs2015或者vs2017,cl才有一个指定源代码字符编码的选项/source-charset,vs2015以前都没有.vs2015以前用vs写c语言程序用utf8编码(没有bom)会有很多问题.总之感谢微软, late better than never!

    使用utf8编码

    假设vs2017的安装目录是%VS_HOME%,则用vs打开下面2个文件

    %VS_HOME%Common7IDEVCvcprojectitemshfile.h
    %VS_HOME%Common7IDEVCvcprojectitems
    ewc++file.cpp
    

    在这2个文件中加入一行中文注释,如

    // utf8编码
    

    然后选择"高级保存选项",然后在编码中选择utf8(无签名)65001.这样再新建文件时,编码都是utf8.

    Hello world程序

    看C00CmdHelloWorld.c的代码:

    // 编码设置为utf-8
    #include <stdio.h>
    #include <string.h>
    int main() {
    	char* a = "hello";
    	char* b = "您好";
    	printf("%s size is %d
    ", a, strlen(a));
    	printf("%s size is %d
    ", b, strlen(b));
    	getchar();
    	return 0;
    }
    

    有2种方式编译运行.

    1. 命令行
      在visual studio tools中打开"develop command prompt for vs2017",进入命令行.切到C00CmdHelloWorld.c所在目录.执行
    cl C00CmdHelloWorld.c /source-charset:utf-8
    C00CmdHelloWorld
    

    输出为

    hello size is 5
    您好 size is 4
    
    1. 用vs
      在vs的工程右键——"属性"——"配制属性"——"C/C++"——"命令行"在其他选项中添加/source-charset:utf-8
      再ctrl+F5运行.结果和命令行运行一致.
      字符串hello的长度是5,没问题."您好"的长度是4,这个是有问题的. 希望得到的长度是2(因为是2个字符.)如何修改?看C00CmdHelloWorld1.c的代码.
    // 编码设置为utf-8
    #include <stdio.h>
    #include <string.h>
    #include <locale.h>
    int main() {
    	_wsetlocale(LC_ALL, L"");
    	wchar_t* a = L"hello";
    	wchar_t* b = L"您好";
    	printf("%ls size is %d
    ", a, wcslen(a));
    	printf("%ls size is %d
    ", b, wcslen(b));
    	getchar();
    	return 0;
    }
    

    这个代码"hello"的长度是5,"您好"的长度是2.wchar_t表示以双字节的方式保存字符.windows用的UCS-2,即以2个字节保存一个字符.这和python2是一样的.但是要兼容以前的程序,单字节的api不能废除掉.微软用了一个技巧,同样一份代码,当没有定义UNICODE宏的时候,使用单字节的api,定义UNICODE宏的时候使用双字节的api.细节见参考资料4的第2章.C00CmdHelloWorld1.c没有用微软这个技巧,显示地指定了用双字节的api.什么时候使用微软这个技巧,什么时候不用?个人建议:

    • 程序不需要GUI界面的时候不用,有非ascii码的代码或数据就显式地用wchar_t.所有代码和数据都是ascii码的时候就用char.
    • 程序中有GUI界面的时候用微软这个技巧.

    GUI消息框的例子

    // C03UnicodeMsg.c编码设置为utf-8
    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    	PSTR szCmdLine, int iCmdShow) {
    	TCHAR szBuffer[100];
    	TCHAR* a = TEXT("a中国b");
    	wsprintf(szBuffer, TEXT("a中国b,len=%d"), _tcslen(a));
    	MessageBox(NULL, szBuffer, TEXT("Hello world汉字"), MB_OK);
    	return 0;
    }
    

    编译这个程序的命令为:

    cl user32.lib gdi32.lib /D UNICODE  / source-charset:utf-8
    

    其中UNICODE就微软定义的宏.这个宏存在时TCHAR被定义为wchar_t,这个宏不存在时,TCHAR被定义为char.

    参考资料

    1. Set Source Character Set
    2. utf-8编码查询
    3. gbk编码查询
    4. (美)Charles Petzold著 方敏,张胜,梁路平,赵勇等译,Windows程序设计(第五版 珍藏版),清华大学出版社,2010.
    5. Continue support for MBCS (Multi-Byte Character Sets) for MFC and C++
  • 相关阅读:
    Json基础知识总结
    java连接mysql
    (原)java中对象复制、==、equals
    方便面为什么要是波浪形的 它是怎么做到的?
    软件测试的基本功
    如何在字符串中找到第一个不重复的字符
    无线信道抗衰落技术
    成都市政府公开电话
    学习使用Robot Framework自动化测试框架-web元素定位
    破解受保护的excel中的密码
  • 原文地址:https://www.cnblogs.com/zhouyang209117/p/7819857.html
Copyright © 2020-2023  润新知