• C++字符集问题终极分析(可解决乱码问题)


    最近研究vc,windows的东西真是很傻瓜,啥都给你做好,有个好处就是开发方便了。

    有个弊端就是完全按微软的一套进行,规则都是它定的,你得知道它的很多api,

    开发出来的代码效率不高,不过却可以比较快的实现一些较好的功能,其实软件开发就应该这样

    要不每个程序员都从0开始做起,那都停留在Hello层次了。其实微软的弊端主要体现在后台的封装,

    开发者无法知道它的api的实现方式;或许某天微软挂了,无数程序员就得上街卖唱乞讨了,

    不过软件行业老大微软可不是那么容易挂的。

    vc中字符处理是一个比较重要的部分,很多初学者对这个都头痛。

    某网友写的关于vc字符集的,看了下还不错,转过来有空看看。

    来源:

    http://blog.csdn.net/phylh/archive/2009/01/21/3847030.aspx

    系统环境
    操作系统                     Windows XP
    本地字符集(MBCS) GBK
    编译器:                     VC8、VC6、DEV-C++(gcc)
    实验字符
    ‘我’
    GBK              字符编码 0xD2CE
    UNICODE     字符编码 0x6211
    ‘a’
    GBK              字符编码 0x61
    UNICODE     字符编码 0x0061
    A-源代码层面
    VC8
    1.         文件首两个字节为 0xFF 0xFE(文本文件开头几个字节标识了源文件使用的字符集,开头为0xFF 0xFE表示使用的是UNICODE字符集),所以源文件以UNICODE方式保存,‘我’字符编码为0x6211,‘a’字符编码为0x0061;
    VC6
    1.         使用本地字符集GBK保存源程序,‘我’字符编码为0xD2CE,‘a’字符编码为0x0061;
    DEV-C++(gcc)
    1.         使用本地字符集GBK保存源程序,‘我’字符编码为0xD2CE,‘a’字符编码为0x0061;
    B-可执行程序层面(源程序字符集->可执行程序字符集)
    VC8
    1.         VC8编译器默认的程序字符集是本地字符集GBK。
    2.         编译参数#pragma setlocale(LOC)告诉编译器源代码字符集为LOC,如果不设置则为UNICODE。
    3.         如果字符字面量前有L(L”我”,L”a”),并且设置了编译参数#pragma setlocale(LOC),那么编译时将发生LOC->UNICODE字符集的转换;假如没有设置则发生源代码字符集UNICODE->UNICODE的转换(相当于不发生转换),’我’的编码是0x6211,’a’的编码是0x0061。
    4.         如果字符字面量前没有L,编译时发生源代码字符集UNICODE->本地字符集GBK编码的转换,’我’的编码是0xD2CE,’a’的编码是0x61。
    VC6
    1.         VC6编译器默认的程序字符集是本地字符集GBK。
    2.         编译参数#pragma setlocale(LOC)告诉编译器源代码字符集为LOC,如果不设置则为系统默认字符集GBK。
    3.         如果字符字面量前有L(L”我”,L”a”),并且设置了编译参数#pragma setlocale(LOC),那么编译时将发生LOC->UNICODE字符集的转换;假如没有设置则发生源代码字符集本地GBK->UNICODE的转换,’我’的编码是0x6211,’a’的编码是0x0061。
    4.         其它情况都不发生任何的字符集编码转换(源程序字符集和程序字符集一致),使用本地字符集GBK编码’,我’的编码是0xD2CE,’a’的编码是0x61。
    DEV-C++(gcc)
    1.         DEV-C++(gcc)编译器默认的程序字符集是UTF-8。
    2.         #pragma setlocale对编译没有影响。
    3.         如果字符字面量前有L(L”我”,L”a”),那么编译时将把字符字面量从配置字符编码GBK转换为UNICODE字符编码(L开头的字符字面量都是使用UNICODE字符编码),’我’的编码是0x6211,’a’的编码是0x0061。注:编译器参数为-finput-charset=GBK(指定源程序字符集为GBK,如果不指定编译器默认源程序字符集为UTF-8)。
    4.         其它情况会发生编译器配置参数GBK->UTF-8字符集的转换,’我’的编码是0x9E88E6,’a’的编码是0x61。这种情况下使用printf打印的时候会出现乱码,由于本地字符集是GBK,但实际字符编码是UTF-8,解决方法是在程序中把UTF-8转换为本地字符集GBK然后再调用printf打印。
    5.         在RH Linux系统下直接调用printf打印不会出问题,因为在该系统下默认字符集是UTF-8和编译器默认字符集一致,所以没有出现乱码问题。
    C-WindowsAPI层面
    VC8
    1.         如果编译参数配置了UNICODE则API被解释为调用UNICODE版本的API(带标记W的API,这里W代表UNICODE字符的含义)。
    2.         如果编译参数没有配置UNICODE则API被解释为调用单字符编码版本的API(带标记A的API)。
    VC6
    同VC8。
    DEV-C++(gcc)
    同VC8。
    D-杂项&总结
    1.         VC中UNICODE编译参数只控制windows API的展开,是UNICODE方式(W标记,这里W代表UNICODE字符的含义)还是单字符方式(A标记),其它不做控制。
    2.         C++中字符字面量前面如果有标识L,程序运行时这个字符字面量一定UNICODE字符编码方式的宽字符(不是其它字符编码方式)。
    3.         C++中如果字符字面量前面没有标识L,那么程序运行时这个字符字面量一定是编译器默认字符集编码方式(VC中是GBK字符集,’我’的编码是0xD2CE,’a’的编码是0x61,DEV-C++中是UTF-8, ’我’的编码是0x9E88E6,’a’的编码是0x61)。
    4.         C++中wchar_t,代表宽字符(UNICODE字符只是宽字符的一种),任何宽字符都可以赋值给wchar_t,包括UNICODE字符和其它宽字符(比如GBK编码的汉字字符),所以理论上wchar_t字符仅仅只代表是宽字符,不代表一定是UNICODE字符(不过一般情况下C++实现都使用UNICODE字符)。

  • 相关阅读:
    Eclipse打包Android项目时用到proguard.cfg后,出现的Warning:can't find referenced class问题的解决方案
    Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
    接口的作用
    Android中Service(服务)详解
    跟 Task 有关的 Intent对象中设置的Flag
    android onNewIntent
    [Android]如何导入已有的外部数据库
    android的文件操作
    MVC 数据验证
    Html辅助方法 之 Form表单标签
  • 原文地址:https://www.cnblogs.com/lidabo/p/8082819.html
Copyright © 2020-2023  润新知