探索printf()为何可以同时输出中英文字符之谜---unicode,UTF-8,字符(上)

来源:互联网 发布:沈阳盘古网络实施顾问 编辑:程序博客网 时间:2024/06/07 02:41

探索printf()为何可以同时输出中英文字符之谜---unicode,UTF-8,字符(上)

                                                                                                                                                                                          jiese1990

        当年风靡全球的C语言,中的经典函数printf(),2年多前在偶的心里深深的留下了印记,“他怎么就可以同时输出中文呢?怎么他就可以同时输出中英文呢?”;也许你会毫不犹豫的说,“很简单嘛,因为unicode嘛!”;那么恭喜你答对一半了。
       有没有试过size=sizeof("jiese戒色");size==????? 16 ? 10 ? 7? 8 ?....我相信有些人会认为答案是16,因为我当时就是那么认为的,嘿嘿。可是当我打开vs2010验证我的想法的时候,答案它居然是...居然是...让人预想不到的10,?我了个去,坑爹的怎么会是10呢。是不是没编译好啊,于是重新生成一遍,还是10,再生成一遍,还是10!再生成一遍,还是10!再生成一遍,还是10.....木有办法,他就是10,静下来好好想想,5个英文字符*x+2中文字符*y+结束符*z==10;拿出小学数学计算的智商 + 2-3年的编程经验得出x=1,y=2,z=1;

       没有错,一定是这样的,我想!当存储ASCII里有的字符时,用的是1byte,存储汉字时2byte!难道莫非,这坑爹字符串混用ASCII和Unicode(如果你也是这么认为的话,那么我可以毫不犹豫的告诉你,“亲,你想多了”)!因为在我的印象里unicode是用2byte表示的字符集,而ASCII则是1byte!

       是的,其实这个印象是没有错的.但是,不要混淆了一个很坑爹的概念“unicode是用2byte表示的字符集!”,但是,没有说,unicode字符都必须用2byte存储!而且,存储的数据未必==Unicode表示字符的数据...等等“表示”和“存储”,“尼玛,坑爹的有木有,2tybe表示,那么不就要2byte存储了!要不怎么能表示?存储的值还不等于unicode字符的值,怎么可能??”也许你心中此时暗骂我。其实我没有说错!可能你还是,不相信我没有坑爹!我只想说“我真的米有坑爹啊”!如果你还是不信,好吧,你妹的,那么,我现在就来证明下我真的不是坑爹的!


证明1:

[cpp] view plaincopy
  1. char cs[4]="一";  
  2. t=t<<8;  
  3. t+=cs[1];  
  4. printf("cs=%d,%d,%d,%d,t=%d---%s\n",cs[0],cs[1],c[2],cs[3],t,cs);  



       输出汉字‘一’的存储值,然后与unicode码对比:


    然而‘一’的unicode值时4e00==19968


   结果证明了:存储的数据未必==Unicode表示字符的数据

证明2:
baidu 异或是google 一下“UTF”;
utf百度百科里说:(点击打开链接)

UTF,通用转换格式
  事实证明,对可以用ASCII表示的字符使用UNICODE并不高效,因为UNICODE比ASCII占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处(我加一句,因为ASCII的字符编码<128)。为了解决这个问题,就出现了一些中间格式的字符集,他们被称为通用转换格式,即UTF(Universal Transformation Format)。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32。本文讨论UTF-8字符集的基础。


在windows核心编程里面也有提到说
UTF-8 UTF-8 encodes some characters as 1 byte, some characters as 2 bytes, some characters as 3 bytes, and some characters as 4 bytes. Characters with a value below 0x0080 are compressed to 1 byte, which works very well for characters used in the United States. Characters between 0x0080 and 0x07FF are converted to 2 bytes, which works well for European and Middle Eastern languages. Characters of 0x0800 and above are converted to 3 bytes, which works well for East Asian languages. Finally, surrogate pairs are written out as 4 bytes. UTF-8 is an extremely popular encoding format, but it's less efficient than UTF-16 if you encode many characters with values of 0x0800 or above.

       其实要我一句话总结下的话,我觉得可以用个比喻:“ ‘情妇’,也可以有很多种叫法,民间俗称'二奶',‘小三’,unicode码就好比‘情妇’,UTF之类的就好比 情妇的其他叫法!虽然指的是同一个东西,但是他们的名词写法不一样,就好比存储方式不一样!”......本来我不想用这么下流的比喻的,可我想,这样的比喻能让人更容易记住Unicode!哎!如比喻当中还有不恰当的地方,还请多多包涵....小的才疏学浅,实在想不出什么更恰当的比喻!要不你来想一个!
       那么答案就....你懂得....

       那么一个字符串如:“12z曾”,那么printf怎么就知道在读该字符串时,该把前三个字节当成3个字符来读,4、5字节当成一个字符来读,6字节当成结束符呢!?!它怎么就这么nb呢!为了窥探其中的秘密,傻乎乎的我曾经剖开printf源码分析,曾经还用循环,输出大量字符的UTF-8的值,然后和unicode值对比,然后根据数据找规律!很不幸的是,没有找到!

不知道,你有没有找到...

可是,亲,你知道吗!真的有规律的!

       答案依然在百度百科:UTF-8 的特性里!

我们先来看一个表有关UTF-8编码规律的
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx


      有没有发现什么规律?很好找的仔细找找,你就会发现!



        没错,printf就是根据第一个字节的高位的连续‘1’的个数来判断,是几字节来共同表示一个字节!然后将整个数据来输出字符的!就是这么简单....

       具体unicode转UTF-8的算法我也没有深究!因为网上有一大有关转换的算法!而且我觉得应该windows有这样的API吧!不过我没有去找....


        好了,也许,你要问研究这东东有神吗用呀?!是的,有什么用啊,2b啊,你研究这个干吗?额....究竟有什么用呢...呵呵,买个官子,下回分解!因为写了这么多很累了,估计你也被我忽悠累了!大家都休息下...


       第一次写技术博文,写的不好的地方望大家多多包涵。

很多东西都是自己摸索中理解的东西,没有老师教,这样一来就不知道有没有错的地方拉,如果发现有错误理解的地方,请及时留言,一起讨论,,小的(jiese1990)将万分感激...感动到,泪流满面.....