• 2011-02-18

    iconv编码转换与字节序有什么关系【总统原创】 - [原创]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://zongtongyi.blogbus.com/logs/105776527.html

    iconv编码转换与字节序有什么关系?为什么UTF8没有字节序的烦恼?

    为什么UTF8不用关心字节序?网上找不到详细说明,引用论坛上一句抱怨的话:
    但是查了N多网页,大家都很坦然的说“UTF-8以字节为编码单元,没有字节序的问题。”,当凭它是字节为编码单元,就没有字节序问题了?这话说的也太厚脸皮了吧。
    是啊,没有详细点的说明啊,只有自己纠结啊。

    首先引入一个程序
    #include
    #define LEN 100
    int main(int argc,char *argv[]){
        iconv_t cd = iconv_open("UTF-8", "zh_TW.big5");    // use UTF-16LE or UTF-16BE
        if (cd == (iconv_t) - 1) {
            printf("open convert library failed.\n");
            exit(1);
        }

        char *pIn, *pOut;
        unsigned int inLen, outLen;

        char encode[]={0x88, 0xEE};
        inLen=2;

        char outbuf[LEN];
        memset(outbuf, '\0', LEN);
        pIn=encode;
        pOut=outbuf;
        outLen=LEN;
        size_t ret;
        ret = iconv(cd, &pIn, &inLen, &pOut, &outLen );
        if (ret == (size_t)-1) {
            fprintf(stdout, "\nconvert failed\n\n");
            return false;
        }

        fprintf(stdout, "\nconvert success\n\n", "  ");
        return (EXIT_SUCCESS);
    } (函数体和头文件有删减,可以自己适当添加后编译)
    解释一下这个程序,这个程序调用系统提供的iconv库来转换编码,其中encode[]数组里是一个big5的编码(这个字的编码是两个字节的,这里用 16进制表示),程序调用iconv库将这个big5编码转换成utf8编码。如果转换成功,则输出“convert success”,否则输出“convert failed”。
    第一个猜想 :只有UTF8编码不需要关心字节序吗?
    问Jacky后得出结论,so far,我们只知道UTF16需要关心字节序,其它全不需要。
    论证一下,只有UTF16的编码单元是双字节的,其它都是单字节的。(又是那个后颜的说法!)
    第二个猜想 :那个encode[]在big endian和little endian中的存储方式有什么不同吗?
    当然,你可以用C语言来解释。不喜欢,来点实验派吧。
    在Solaris中,用dbx调试一下,实验机器分别是一台Sparc,一台x86,Sparc是big endian,x86是little endian。
    根据实验结果,不论是Sparc,还是x86,从内存地址上,encode[2] > encode[1] > encode[0]
    也就是说不论是big endian还是little endian,数组都是递增存储的。(挺废话的)
    有以上铺垫后延伸:根据iconv源码,iconv读入调用者给出的inbuffer地址,然后递增的去分析每个字节 (i++)
    例:gbk_encode[2]={0x8F, 0xEC}; 其中gbk_encode[0]存在内存地址0x000081,则gbk_encode[1]存在内存地址0x000082
    首先,不论big endian还是little endian,数组在内存中都是这么递增存储的,
    其次,不论big endian还是little endian,iconv源码都是从内存中递增去读取数据的,
    则,不论big endian还是little endian,读出来的都是相同的结果,
    所以,我们证明了:单字节编码的字符集,不需要考虑字节序问题。
    那...双字节为什么不一样呢?
    第三个猜想 :一个汉字,在big endian机器上存储到文件里,与little endian有什么不一样的?
    麻烦,随便找台机器,打开gedit,输入“我”,分别以“Unicode(UTF-16BE)”和“Unicode(UTF-16LE)”两种编码方式保存,即分别按big endian和little endian方式存储。
    文件名分别为be和le,再用gedit打开,当然,还是看到“我”字,因为gedit能自动识别编码嘛。
    怎么看呢?用vi,“vi -b be”和“vi -b le”,以二进制方式打开,进入vi后,输入命令":%!xxd",回车,则看到了改文件对应的二进制,
    be文件的二进制是:6211
    le文件的二进制是:1162
    明白了吗,还没明白,对啊,看iconv源码,UTF16对应的实现文件是UTF8%...,通过条件编译来编译出UTF16_BE等的版本,不细说这个,看代码,当处理little endian的时候,iconv对inbuffer的处理是反过来读的。
    该下班了,差不多就这样了。


    历史上的今天:


    收藏到:Del.icio.us




    评论

  • 写得不错~学习了~~