zoukankan      html  css  js  c++  java
  • 文件编码和文件内的字符串字面值编码是两个概念

    我们知道,CALabel的字符串使用的是UTF8编码,
    通常在xcode下,直接CALabel *p = ...; p->setText("汉字"),显示汉字是没有任何问题的,
    但是,在VS2013中却显示的是乱码。
    很多人在群里面问了,我都答:请使用UTF8编码。
    他说,我的文件是UTF8格式的啊。呵呵,没那么简单好吗,文件编码和字符串字面值编码是两个概念。

    VS2013的一条预编译指令
    #pragma execution_character_set("utf-8") 
    这下就可以放心地在VS2013里面p->setText("汉字"),p->setText("中文")了
    由于它只是一条预编译指令,一般将这句放在include群后面就好了

    VC2010下c++源码的字符串的中文乱码问题

    要搞清楚这个问题,先要弄明白编码。但是编码问题实在太复杂,这里肯定讲不开。

    我先找一个例子,比如:"中文" 的 Unicode 码点/UTF8编码/GBK 分别是多少。

    先去这个网站,输入 "中文" 查询对应的 Unicode 码点/UTF8编码:http://www.mytju.com/classcode/tools/encode_utf8.asp

    Unicode的码点分别是(十进制):中(20013),文(25991)。 对应的UTF8编码分别(16进制): 中(E4B8AD),文(E69687)。

    然后再去下面这个网站,输入 "中文" 查询对应的 GBK 编码:http://www.mytju.com/classcode/tools/encode_gb2312.asp

    GBK编码16进制(GBK内码)分别是:中(D6D0),文(CEC4)。

    现在已经知道了"中文"的UTF8和GBK编码的具体值。 我们再看看VC2010是怎么处理的。

    1. 先看 无 BOM 的 UTF8 编码的代码 (utf8_no_bom.cpp)

    // utf8 no bom
    // 文件中包含不能在当前代码页(936)中表示的字符
    #include <stdio.h>
    
    int main() {
        const char* str = "中文";
        for(int i = 0; i < sizeof(str); ++i) {
            printf("0x%x ", str[i]&0xFF);
        }
        return 0;
        // Output:
        // 0xe4 0xb8 0xad 0xe6
    }

    输出是:0xe4 0xb8 0xad 0xe6。 感觉好像是对的。

    但是,先别急:VC编译时输出了一条警告信息: utf8nobom.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。 请将该文件保存为 Unicode 格式以防止数据丢失。

    潜台词就是,你这个代码有GBK不能表示的字符,请用Unicode方式保存。 VC根本就没把 代码(utf8nobom.cpp) 当作UTF8,VC只是把它作为GBK处理罢了。

    那为什么又输出了正确的结果呢?

    因为 VC 把 (utf8nobom.cpp) 当作 GBK,而编译时也要转换为本地编码(也是GBK)。 因此,UTF8编码的 "中文",被VC当作编码为 "0xe4 0xb8 0xad 0xe6" 的其他中文处理了。 VC已经不知道 "0xe4 0xb8 0xad 0xe6" 是对应 "中文" 字面值了。

    但是在GBK(实际是无BOM的UTF8)转GBK的过程中,发现了一些UTF8编码的字符并不是 GBK能表达的合理方式,因此就出现了那个C4819编译警告。

    2. 再看带BOM的UTF8是怎么处理的 (utf8_with_bom.cpp)

    // utf8 with bom
    #include <stdio.h>
    
    int main() {
        const char* str = "中文";
        for(int i = 0; i < sizeof(str); ++i) {
            printf("0x%x ", str[i]&0xFF);
        }
        return 0;
        // Output:
        // 0xd6 0xd0 0xce 0xc4
    }

    编译没有警告,但是输出有问题:0xd6 0xd0 0xce 0xc4。

    源文件明明是 UTF8 编码的格式"0xe4 0xb8 0xad 0xe6", 怎么变成了 "0xd6 0xd0 0xce 0xc4" (这个是GBK编码)?

    这就是VC私下干的好事:它自作聪明的将UTF8源代码转换为GBK处理了!

    VC为何要做这样蠢事?

    原因是为了兼容老的VC版本。 因为以前的VC不能处理UTF8,都是用本地编码处理的。

    3. 在看看真的GBK是怎么处理的 (gbk.cpp)

    // gbk
    #include <stdio.h>
    
    int main() {
        const char* str = "中文";
        for(int i = 0; i < sizeof(str); ++i) {
            printf("0x%x ", str[i]&0xFF);
        }
        return 0;
        // Output:
        // 0xd6 0xd0 0xce 0xc4
    }

    没有编译错误,输出也和源代码一致:"0xd6 0xd0 0xce 0xc4"。

    因为源文件就是GBK,cl在编译时GBK转化为GBK,没有改变字符串。

    只是,现在很多人不想用GBK了(因为只能在中国地区用,不能表示全球字符)。

     

    到这里,可以初步小结一下:

    1. VC编辑器和VC编译器是2个概念,VC编辑器支持UTF8并不能表示VC编译器也支持UTF8

    2. VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏,因为会本地编码冲突)

    3. VC编译器从2010开始重要可以支持UTF8了(虽然支持方式很不优雅)

       

    4. 看看VC2010是怎么处理带BOM的UTF8的 (utf8_with_bom_2010.cpp)

    VC2010重要增加了UTF8的编译支持(#pragma execution_character_set("utf-8")), 具体查看:

    http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec

    // utf8 with bom (VC2010), 这句是重点!
    #pragma execution_character_set("utf-8")
    
    #include <stdio.h>
    
    int main() {
        const char* str = "中文";
        for(int i = 0; i < sizeof(str); ++i) {
            printf("0x%x ", str[i]&0xFF);
        }
        return 0;
        // Output:
        // 0xe4 0xb8 0xad 0xe6
    }

    没有编译错误,输出也和源代码一致:"0xe4 0xb8 0xad 0xe6"。

    UTF8编码,UTF8输出。完美!

    1. VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏,因为会本地编码冲突)---原因:

      微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开。BOM 字节序列 在utf-8 其实是无意义的, 再UTF-16 或者 UTF-32 里面才有意义。

    转载:https://m.oschina.net/blog/161676

    http://www.zhihu.com/question/20167122

  • 相关阅读:
    MVC知识点01
    MVC知识点02
    ADO.NET基础01
    WinForm,MVC知识点
    C#基础01
    28、对多次使用的RDD进行持久化或Checkpoint
    27、优化数据结构
    26、高性能序列化类库
    25、诊断内存的消耗
    24、Checkpoint原理剖析
  • 原文地址:https://www.cnblogs.com/porter/p/4909856.html
Copyright © 2011-2022 走看看