• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 319, comments - 22, trackbacks - 0, articles - 11
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            15款很棒的 JavaScript 開發工具

            ugmbbc發布于 2011-05-17 14:18:36|3743 次閱讀 字體: 打印預覽 分享至新浪微博 轉貼到開心網 分享到校內人人網 添加到Google書簽

            網絡軟件

            感謝山邊小溪的投遞
            在開發中,借助得力的工具可以事半功倍。今天,這篇文章向大家分享最新收集的15款非常有用的 JavaScript 開發工具。
            TestSwarm: Continious & Distributed JS Testing

            TestSwarm是Mozilla實驗室推出的一個開源項目,它旨在為開發者提供在多個瀏覽器版本上快速輕松測試自己JavaScript代碼的方法。
            Javascript-212 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            Minimee
            在網絡上,速度是很重要的,Minimee能幫助你將CSS和JavaScript文件進行自動壓縮和打包。
            Javascript-169 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            Doctor JS
            Doctor JS 是一款幫你分析 JavaScript 代碼的工具,測試你的代碼在多態、原型、異常和回調方面寫得怎么樣。
            Javascript-174 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            Remy Sharp’s JSConsole
            一個在線的 JavaScript 控制臺工具,對于測試、調試和演示非常有用。
            Javascript-269 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            JavaScript Library Boilerplate
            JavaScript Library Boilerplate 幫助你隨時隨地創建自己的 JavaScript 庫。
            Javascript-260 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            jsdoc-toolkit
            JsDoc Toolkit 是一款輔助工具,你只需要根據約定在 JavaScript 代碼中添加相應的注釋,它就可以根據這些注釋來自動生成API文檔。
            Js-010 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            Jasmine: BDD for your JavaScript
            Jasmine 是一個有名的javascript單元測試框架,它是獨立的“行為驅動開發”框架。
            Js-011 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            ObfuscateJS: JavaScript compressor
            一款 JavaScript 混淆工具,去除空白和注釋,重命名變量等。
            Javascript-282 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            PEG.js
            PEG.js 是一個JavaScript的表達式語法解析器,它使您能夠輕松地建立復雜的數據或計算機程序語言的快速分析器。
            Javascript-228 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            JSONView
            JSONView 是一款幫助你在瀏覽器中查看JSON文檔的Firefox插件。
            Js-014 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            JSonduit
            JSonduit 是一個將網頁內容轉換為 JSON 格式訂閱器的工具。
            Javascript-182 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            jsplumb
            jsPlumb 為開發者提供了可視化鏈接元素到頁面的方法,可以結合jQuery、MooTools 和 YUI3使用。
            Javascript-193 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            Helma
            Helma 是一個用來開發快速、穩定的Web應用程序的開源框架,它使用JavaScript 來作為服務端腳本環境,從而可以省略編譯周期。
            Js-015 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            HTML + JSON Report
            一款將 JSON 數據轉換為可讀性更高的HTML格式內容的在線工具。
            Javascript-300 in Useful JavaScript and jQuery Tools, Libraries, Plugins

            JSON Editor
            這個編輯器可以幫助你方便的編輯 JSON 字符串。
            Javascript-222 in Useful JavaScript and jQuery Tools, Libraries, Plugins
            你可能還喜歡

          1. 推薦40個優秀的免費CSS工具
          2. 分享18個常用的網站性能測試工具
          3. 推薦25個提高網站可用性和轉化率的工具
          4. JavaScript初學者應注意的七個細節
          5. 你可能不知道的10個JavaScript小技巧

          6. (編譯來源:夢想天空  原文來自:Useful JavaScript and jQuery Tools, Libraries, Plugins

             

            posted @ 2011-05-17 18:59 RTY 閱讀(320) | 評論 (0)編輯 收藏

            VirtualBox 宣布了 4.0.8 版本,該版本改進了對 Gnome 3 的 3D 支持。同時還修復了不少bug,包括改變 guest 窗體大小時可能導致程序崩潰的問題以及 Ubuntu 11.04 以及 Fedora 15 下 Gnome 3 的渲染問題。

            VirtualBox 是一款功能強大的 x86 虛擬機軟件,它不僅具有豐富的特色,而且性能也很優異。

            更多關于VirtualBox的詳細信息,或者下載地址請點這里

            posted @ 2011-05-17 18:55 RTY 閱讀(382) | 評論 (0)編輯 收藏

            20+ Useful jQuery Content Slider Scripts and Tutorials

            Posted by: Adrian, In: Coding, Tutorials, On: May 16, 2011 | 2 Comments

            Maybe you’ve seen some businesses with beautifully designed websites that also have a slider which displays their available products and services; and since then you’ve been asking yourself how it’s done? If you still haven’t found out, then lend me an ear, because here’s the answer. It’s done with jQuery.

            So what is jQuery? As you probably know, there’s JavaScript – a scripting language, but Query is just a branch. jQuery is used to make easier the effects and interaction with the development code and works just like JavaScript. Released in January 2006, it gains popularity pretty quickly as it’s a nice technology that helps making the websites over the internet more interactive and fun. Also it takes less code than with JavaScript to create effects like drop down menus, animations, drag and drop elements and form validation.

            So, as it is easy and simple to use, needs less coding and creates interesting and beautiful effects, why not try making a slider with your recent products to put on your website? Here are 20+ of the most useful jQuery content slider scripts and tutorials. Hope to have inspired at least some of you and soon we will see more sites that are interactive and client oriented, saving space and showcasing their offer into nicely designed sliders.

            Rotating Image Slider with jQuery

            Parallax Slider with jQuery

            Compact News Previewer with jQuery

            Awkward Showcase – A jQuery Plugin

            WOW Slider

            Automatic Image Slider w/ CSS & jQuery

            Making a Mosaic Slideshow With jQuery & CSS

            How to Make Auto-Advancing Slideshows

            Coding a Rotating Image Slideshow w/ CSS3 and jQuery

            Create Beautiful jQuery slider tutorial

            CU3ER Image Slider

            jQueryGlobe – jQuery Plugin

            Nivo Slider

            Piecemaker XML Gallery

            Slide Deck

            Slides

            Slider Gallery with jQuery

            Estro – jQuery Ken Burns & swipe effect slider

            FSS – Full Screen Sliding Website Plugin

            li JQuery Slider/Image Rotator

            Point of ViUU

            posted @ 2011-05-17 18:52 RTY 閱讀(617) | 評論 (0)編輯 收藏

            IntelliJ IDEA 10.5 正式版發布了,建議所有人升級。IDEA 10.5 是一個重要的升級版本,該版本主要的改進包括:

            • 完全支持 Java 7

              Java 7 migration helpers

            • 重構功能、搜索替換功能界面的重構,簡化代碼自動完成

              In-place search-replace


              In-place introduce refactorings

            • 支持 Chrome 的 JavaScript 調試器
            • 支持 Groovy 1.8 和 Spring 3.1

              Shift-less code completion

              Spring 3.1 profiles

               

            • JavaScript, Android and Flex 開發改進
            • Jetty 集成
            • XSLT2 支持

            完整內容請看官方發行說明:http://www.jetbrains.com/idea/whatsnew/

            posted @ 2011-05-17 18:50 RTY 閱讀(644) | 評論 (0)編輯 收藏

            安裝Msysgit

            下一步

            同意GNU協議

            選擇安裝位置,下一步

            選擇TrueType  Front,下一步

            不創建啟動文件夾

            默認Git Bash,就可以了

            選擇使用OpenSSH

            選擇默認的Checkout Style

            安裝完成了

            配置本地的Git

            就這樣安裝好Msysgit后,就可以開始配置開發環境了,在你的工作目錄建立一個新的文件夾Git,比如我的

            選擇Git文件夾,右鍵,選擇Git Bash Here,會彈出shell命令行界面

            生成你的Public Key

            輸入命令

            ssh-keygen –C “你的email地址 “ –t rsa

            就會為你生成一個 SSH Key,然后會詢問一些保存文件的位置,設置密碼神馬的,直接回車,回車,回車,默認的就可以了

            因為主要是在本地使用,可不使用口令,直接回車就可以了!

            好了,現在為你生成了sshkey了。

            設置Github帳號的Public Key

            如果你有一個github的賬號的話,

            登陸github.Com 網站,在SSH Public Keys 設置你的SSH Public Keys

            創建一個數據倉庫

            設置相關的信息

            設置你的Email和Nickname

            現在回到你的工作目錄,可以選擇設置你默認的email和nickname
            輸入命令

            git config –global user.email 你的email地址
            git config –global user.name "Arthur"

            Clone你的項目

            右鍵你的工作目錄Git,選擇Git GUI,選擇克隆已有版本庫

            輸入你在github的項目地址,例如

            git@github.com:caijiamx/Magento-Theme.git

            會彈出一個框出來讓你是否選擇信任github,輸入yes

            然后就會從github拉取數據了,

            前面簡單的介紹如何克隆版本庫,現在就要正式的開始工作了。

            命令行下的Git開發

            新建一個工作文件夾,右鍵打開 Git Bash,輸入

            ssh git@github.com

            選擇yes,加入到hosts中

            信任git@github.com站點

            配置你的Github上Username和Token

            設置你的github 用戶名

            git config –global github.user caijiamx

            設置你的git賬戶的token

            Git config –global github.token your token

            這個token在github,com的Account Settings->Account Admin右側找到。

            我們重新開始上面介紹的從GUI拉取數據,現在我們從命令開始你的項目

            Git下的開發

            為你的項目添加說明文件

            touch readme.txt
            //輸入hello world

            將新建的文件添加到暫存區,輸入命令

            git add readme.txt

            提交你的更改 輸入命令

            git commit –m "first commit"

            添加遠程服務器倉庫,輸入命令

            git remote add origin git@github.com:directoo/Magento-Theme.git

            提交你的更改到服務器,輸入命令

            git push origin master

            參考資源

            github set up git

            如何設置你的SSH Key

            github官方幫助教程

            初次運行 Git 前的配置

            posted @ 2011-05-15 00:30 RTY 閱讀(848) | 評論 (0)編輯 收藏

            1、Run-Time Library

            Run-Time Library是編譯器提供的標準庫,提供一些基本的庫函數和系統調用。
            我們一般使用的Run-Time Library是C Run-Time Libraries。當然也有Standard C++ libraries。 
            C Run-Time Libraries實現ANSI C的標準庫。VC安裝目錄的CRT目錄有C Run-Time庫的大部分源代碼。

            C Run-Time Libraries有靜態庫版本,也有動態鏈接庫版本;有單線程版本,也有多線程版本;還有調試和非調試版本。
            可以在"project"-"settings"-"C/C++"-"Code Generation"中選擇Run-Time Library的版本。

            動態鏈接庫版本:
            /MD Multithreaded DLL 使用導入庫MSVCRT.LIB
            /MDd Debug Multithreaded DLL 使用導入庫MSVCRTD.LIB

            靜態庫版本:
            /ML Single-Threaded 使用靜態庫LIBC.LIB 
            /MLd Debug Single-Threaded 使用靜態庫LIBCD.LIB
            /MT Multithreaded 使用靜態庫LIBCMT.LIB
            /MTd Debug Multithreaded 使用靜態庫LIBCMTD.LIB

            C Run-Time Library的標準io部分與操作系統的關系很密切,在Windows上,CRT的io部分代碼只是一個包裝,底層要用到操作系統內核kernel32.dll中的函數,在編譯時使用導入庫kernel32.lib。這也就是為什么在嵌入式環境中,我們一般不能直接使用C標準庫。
            在Linux環境當然也有C標準庫,例如:
            ld -o output /lib/crt0.o hello.o -lc
            參數"-lc"就是在引用C標準庫libc.a。猜一猜"-lm"引用哪個庫文件?

            2、常見的編譯參數

            VC建立項目時總會定義"Win32"??刂婆_程序會定義"_CONSOLE",否則會定義"_WINDOWS"。Debug版定義"_DEBUG",Release版定義"NDEBUG"

             

            與MFC DLL有關的編譯常數包括:
            _WINDLL 表示要做一個用到MFC的DLL
            _USRDLL 表示做一個用戶DLL(相對MFC擴展DLL而言) 
            _AFXDLL 表示使用MFC動態鏈接庫
            _AFXEXT 表示要做一個MFC擴展DLL
            所以:
            Regular, statically linked to MFC _WINDLL,_USRDLL 
            Regular, using the shared MFC DLL _WINDLL,_USRDLL,_AFXDLL
            Extension DLL _WINDLL,_AFXDLL,_AFXEXT

            CL.EXE編譯所有源文件,LINK.EXE鏈接EXE和DLL,LIB.EXE產生靜態庫。

            3、subsystem和可執行文件的啟動

            LINK的時候需要指定/subsystem,這個鏈接選項告訴Windows如何運行可執行文件。
            控制臺程序是/subsystem:"console"
            其它程序一般都是/subsystem:"windows "

             

            將 subsystem 選成"console"后,Windows在進入可執行文件的代碼前(如mainCRTStartup),就會產生一個控制臺窗口。
            如果選擇"windows",操作系統就不產生console窗口,該類型應用程序的窗口由用戶自己創建。

            可執行文件都有一個Entry Point,LINK時可以用/entry指定。缺省情況下,如果subsystem是“console”,Entry Point是 mainCRTStartup(ANSI)或wmainCRTStartuup(UNICODE),即:
            /subsystem:"console" /entry:"mainCRTStartup" (ANSI)
            /subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)
            mainCRTStartup 或 wmainCRTStartuup 會調用main或wmain。
            值得一提的是,在進入應用程序的Entry Point前,Windows的裝載器已經做過C變量的初始化,有初值的全局變量擁有了它們的初值,沒有初值的變量被設為0。

            如果subsystem是“windows”,Entry Point是WinMain(ANSI)或wWinMain(UINCODE),即:
            /subsystem:"windows" /entry:"WinMainCRTStartup" (ANSI)
            /sbusystem:"windows" /entry:"wWinMainCRTStartup" (UINCODE)
            WinMainCRTStartup 或 wWinMainCRTStartup 會調用 WinMain 或 wWinMain。

            這些入口點函數,在CRT目錄都可以看到源代碼,例如(為了簡潔,我刪除了原代碼的一些條件編譯):

            void mainCRTStartup(void)
            {
                    int mainret;
            
                    /* Get the full Win32 version */
                    _osver = GetVersion();
                    _winminor = (_osver >> 8) & 0x00FF ;
                    _winmajor = _osver & 0x00FF ;
                    _winver = (_winmajor << 8) + _winminor;
                    _osver = (_osver >> 16) & 0x00FFFF ;
            
            #ifdef _MT
                    if ( !_heap_init(1) )               /* initialize heap */
            #else  /* _MT */
                    if ( !_heap_init(0) )               /* initialize heap */
            #endif  /* _MT */
                        fast_error_exit(_RT_HEAPINIT);  /* write message and die */
            
            #ifdef _MT
                    if( !_mtinit() )                    /* initialize multi-thread */
                        fast_error_exit(_RT_THREAD);    /* write message and die */
            #endif  /* _MT */
            
                    __try {
                        _ioinit();                      /* initialize lowio */
                        _acmdln = (char *)GetCommandLineA();        /* get cmd line info */
                        _aenvptr = (char *)__crtGetEnvironmentStringsA();        /* get environ info */
                        _setargv();
                        _setenvp();
                        __initenv = _environ;
                        mainret = main(__argc, __argv, _environ);
                        exit(mainret);
                    }
                    __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
                    {
                        _exit( GetExceptionCode() );        /* Should never reach here */
                    } /* end of try - except */
            }  

            如果使用MFC框架,WinMain也會被埋藏在MFC庫中(APPMODUL.CPP):
            extern "C" int WINAPI
            _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPTSTR lpCmdLine, int nCmdShow)
            {
            // call shared/exported WinMain
            return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
            }
            對于ANSI版本,"_tWinMain"就是"WinMain";對于UINCODE版本,"_tWinMain"就是"wWinMain"??蓞⒁奱fx.h:

            #ifdef _UNICODE
            #define _tmain wmain
            #define _tWinMain wWinMain
            #else
            #define _tmain main
            #define _tWinMain WinMain
            #endif

            全局C++對象的構造函數是在什么地方調用的?答案是在進入應用程序的Entry Point后,在調用main函數前的初始化操作中。所以MFC的theApp的構造函數是在_tWinMain之前調用的。

            4、不顯示Console窗口的Console程序

            在默認情況下/subsystem 和/entry開關是匹配的,也就是:
            "console"對應"mainCRTStartup"或者"wmainCRTStartup"
            "windows"對應"WinMain"或者"wWinMain"
            我們可以通過手動修改的方法使他們不匹配。例如:

             

            #include "windows.h"
            #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 設置入口地址 
            void main(void)
            {
            MessageBox(NULL, "hello", "Notice", MB_OK);
            }

            這個Console程序就不會顯示Console窗口。如果選/MLd的話,這個程序只需要鏈接LIBCD.LIB user32.lib kernel32.lib。

            其實如果不想看到Console窗口,還有一個更直接的方法:那就是直接在EXE文件中將PE文件頭的Subsystem從3改成2。在EXE文件中,PE文件頭的偏移地址是0x3c,Subsystem是一個WORD,它在PE文件頭中的偏移是0x5c。

            5、MFC的庫文件

            MFC的庫可以靜態鏈接,也可以動態鏈接。靜態庫和動態庫又有Debug和Release,ANSI和Unicode版本之分。

             

            靜態MFC庫主要有:
            ANSI Debug NAFXCWD.LIB
            ANSI Release NAFXCW.LIB
            Unicode Debug UAFXCWD.LIB
            Unicode Release UAFXCW.LIB 

            動態鏈接庫主要有;
            ANSI Debug MFCxxD.LIB (core,MFCxxD.DLL), 
            MFCOxxD.LIB (OLE,MFCOxxD.DLL), 
            MFCDxxD.LIB (database,MFCDxxD.DLL), 
            MFCNxxD.LIB (network,MFCNxxD.DLL), 
            MFCSxxD.LIB (static)

            ANSI Release MFCxx.LIB (combined,MFCxx.DLL)
            MFCSxx.LIB (static)

            Unicode Debug MFCxxUD.LIB (core,MFCxxUD.DLL), 
            MFCOxxUD.LIB (OLE,MFCOxxUD.DLL), 
            MFCDxxUD.LIB (database,MFCDxxUD.DLL), 
            MFCNxxUD.LIB (network,MFCNxxUD.DLL), 
            MFCSxxUD.LIB (static)

            Unicode Release MFCxxU.DLL (combined,MFCxxU.DLL), 
            MFCSxxU.LIB (static)

            上面的LIB文件除了MFCSxx(D、U、UD).LIB以外都是導入庫。
            MFC動態鏈接庫版本也需要靜態鏈接一些文件,這些文件就放在MFCSxx(D、U、UD).LIB中。例如包含_tWinMain的appmodul.cpp。

            6、結束語

            研究這些問題的動機是想弄清楚我們的程序是如何裝載、運行的。但是,由于Windows不是開源平臺,我也只能研究到PE文件(Windows上可執行文件的格式)。entry point、subsystem都是PE文件頭的一部分。

            Windows在進入PE文件的entry point之前做了些什么,就看不到了,只能大概推測:應該是創建一個進程,裝載PE文件和所有需要的DLL,初始化C變量,然后從某個起點函數開始運行。不同的subsystem,應該有不同的起點。調用這個起點函數時應該傳入PE文件的entry point地址。

             

            posted @ 2011-05-12 22:06 RTY 閱讀(520) | 評論 (0)編輯 收藏

            1 什么是堆棧

            編譯器一般使用堆棧實現函數調用。堆棧是存儲器的一個區域,嵌入式環境有時需要程序員自己定義一個數組作為堆棧。Windows為每個線程自動維護一個堆棧,堆棧的大小可以設置。編譯器使用堆棧來堆放每個函數的參數、局部變量等信息。

            函數調用經常是嵌套的,在同一時刻,堆棧中會有多個函數的信息,每個函數占用一個連續的區域。一個函數占用的區域被稱作幀(frame)。

            編譯器從高地址開始使用堆棧。 假設我們定義一個數組a[1024]作為堆??臻g,一開始棧頂指針指向a[1023]。如果棧里有兩個函數a和b,且a調用了b,棧頂指針會指向函數b的幀。如果函數b返回。棧頂指針就指向函數a的幀。如果在棧里放了太多東西造成溢出,破壞的是a[0]上面的東西。

            在多線程(任務)環境,CPU的堆棧指針指向的存儲器區域就是當前使用的堆棧。切換線程的一個重要工作,就是將堆棧指針設為當前線程的堆棧棧頂地址。

            不同CPU,不同編譯器的堆棧布局、函數調用方法都可能不同,但堆棧的基本概念是一樣的。

            2 函數調用約定

            函數調用約定包括傳遞參數的順序,誰負責清理參數占用的堆棧等,例如 :

             參數傳遞順序誰負責清理參數占用的堆棧
            __pascal從左到右調用者
            __stdcall從右到左被調函數
            __cdecl從右到左調用者

            調用函數的代碼和被調函數必須采用相同的函數的調用約定,程序才能正常運行。在Windows上,__cdecl是C/C++程序的缺省函數調用約定。

            在有的cpu上,編譯器會用寄存器傳遞參數,函數使用的堆棧由被調函數分配和釋放。這種調用約定在行為上和__cdecl有一個共同點:實參和形參數目不符不會導致堆棧錯誤。

            不過,即使用寄存器傳遞參數,編譯器在進入函數時,還是會將寄存器里的參數存入堆棧指定位置。參數和局部變量一樣應該在堆棧中有一席之地。參數可以被理解為由調用函數指定初值的局部變量。

            3 例子:__cdecl和__stdcall

            不同的CPU,不同的編譯器,堆棧的布局可能是不同的。本文以x86,VC++的編譯器為例。

            VC++編譯器的已經不再支持__pascal, __fortran, __syscall等函數調用約定。目前只支持__cdecl和__stdcall。

            采用__cdecl或__stdcall調用方式的程序,在剛進入子函數時,堆棧內容是一樣的。esp指向的棧頂是返回地址。這是被call指令壓入堆棧的。下面是參數,左邊參數在上,右邊參數在下(先入棧)。

            如前表所示,__cdecl和__stdcall的區別是:__cdecl是調用者清理參數占用的堆棧,__stdcall是被調函數清理參數占用的堆棧。

            由于__stdcall的被調函數在編譯時就必須知道傳入參數的準確數目(被調函數要清理堆棧),所以不能支持變參數函數,例如printf。而且如果調用者使用了不正確的參數數目,會導致堆棧錯誤。

            通過查看匯編代碼,__cdecl函數調用在call語句后會有一個堆棧調整語句,例如:

              a = 0x1234;
              b = 0x5678;
              c = add(a, b);

            對應x86匯編:

              mov dword ptr [ebp-4],1234h
              mov dword ptr [ebp-8],5678h
              mov eax,dword ptr [ebp-8]
              push eax
              mov ecx,dword ptr [ebp-4]
              push ecx
              call 0040100a
              add esp,8
              mov dword ptr [ebp-0Ch],eax


            __stdcall的函數調用則不需要調整堆棧:

              call 00401005
              mov dword ptr [ebp-0Ch],eax

            函數

              int __cdecl add(int a, int b)
              {
              return a+b;
              }

            產生以下匯編代碼(Debug版本):

              push ebp
              mov ebp,esp
              sub esp,40h
              push ebx
              push esi
              push edi
              lea edi,[ebp-40h]
              mov ecx,10h
              mov eax,0CCCCCCCCh
              rep stos dword ptr [edi]
              mov eax,dword ptr [ebp+8]
              add eax,dword ptr [ebp+0Ch]
              pop edi
              pop esi
              pop ebx
              mov esp,ebp
              pop ebp
              ret // 跳轉到esp所指地址,并將esp+4,使esp指向進入函數時的第一個參數

            再查看__stdcall函數的實現,會發現與__cdecl函數只有最后一行不同:

              ret 8 // 執行ret并清理參數占用的堆棧

            對于調試版本,VC++編譯器在“直接調用地址”時會增加檢查esp的代碼,例如:

              ta = (TAdd)add; // TAdd定義:typedef int (__cdecl *TAdd)(int a, int b);
              c = ta(a, b);

            產生以下匯編代碼:

              mov [ebp-10h],0040100a
              mov esi,esp
              mov ecx,dword ptr [ebp-8]
              push ecx
              mov edx,dword ptr [ebp-4]
              push edx
              call dword ptr [ebp-10h]
              add esp,8
              cmp esi,esp
              call __chkesp (004011e0)
              mov dword ptr [ebp-0Ch],eax

            __chkesp 代碼如下。如果esp不等于函數調用前保存的值,就會轉到錯誤處理代碼。

              004011E0 jne __chkesp+3 (004011e3)
              004011E2 ret
              004011E3 ;錯誤處理代碼

            __chkesp的錯誤處理會彈出對話框,報告函數調用造成esp值不正確。 Release版本的匯編代碼要簡潔得多。也不會增加 __chkesp。如果發生esp錯誤,程序會繼續運行,直到“遇到問題需要關閉”。

            3 補充說明

            函數調用約定只是“調用函數的代碼”和被調用函數之間的關系。

            假設函數A是__stdcall,函數B調用函數A。你必須通過函數聲明告訴編譯器,函數A是__stdcall。編譯器自然會產生正確的調用代碼。

            如果函數A是__stdcall。但在引用函數A的地方,你卻告訴編譯器,函數A是__cdecl方式,編譯器產生__cdecl方式的代碼,與函數A的調用約定不一致,就會發生錯誤。

            以delphi調用VC函數為例,delphi的函數缺省采用__pascal約定,VC的函數缺省采用__cdecl約定。我們一般將VC的函數設為__stdcall,例如:

              int __stdcall add(int a, int b);

            在delphi中將這個函數也聲明為__stdcall,就可以調用了:

              function add(a: Integer; b: Integer): Integer;
              stdcall; external 'a.dll';

            因為考慮到可能被其它語言的程序調用,不少API采用__stdcall的調用約定。

            posted @ 2011-05-12 22:00 RTY 閱讀(463) | 評論 (0)編輯 收藏

            3 字符編碼模型

            程序員經常會面對復雜的問題,而降低復雜性的最簡單的方法就是分而治之。Peter Constable在他的文章"Character set encoding basics Understanding character set encodings and legacy encodings"中描述了字符編碼的四層模型。我覺得這種說法確實可以更清晰地展現字符編碼中發生的事情,所以在這里也介紹一下。

            3.1 字符的范圍(Abstract character repertoire)

            設計字符編碼的第一層就是確定字符的范圍,即要支持哪些字符。有些編碼方案的字符范圍是固定的,例如ASCII、ISO 8859 系列。有些編碼方案的字符范圍是開放的,例如Unicode的字符范圍就是世界上所有的字符。

            3.2 用數字表示字符(Coded character set)

            設計字符編碼的第二層是將字符和數字對應起來??梢詫⑦@個層次理解成數學家(即從數學角度)看到的字符編碼。數學家看到的字符編碼是一個正整數。例如在Unicode中:漢字“字”對應的數字是23383。漢字“”對應的數字是134192。

            在寫html文件時,可以通過輸入"字"來插入字符“字”。不過在設計字符編碼時,我們還是習慣用16進制表示數字。即將23383寫成0x5BD7,將134192寫成0x20C30。

            3.3 用基本數據類型表示字符(Character encoding form)

            設計字符編碼的第三層是用編程語言中的基本數據類型來表示字符??梢詫⑦@個層次理解成程序員看到的字符編碼。在Unicode中,我們有很多方式將數字23383表示成程序中的數據,包括:UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的縮寫,可以翻譯成Unicode字符集轉換格式,即怎樣將Unicode定義的數字轉換成程序數據。例如,“漢字”對應的數字是0x6c49和0x5b57,而編碼的程序數據是:

             

            	BYTE data_utf8[] = {0xE6, 0xB1, 0x89, 0xE5, 0xAD, 0x97};	// UTF-8編碼
            	WORD data_utf16[] = {0x6c49, 0x5b57};				// UTF-16編碼
            	DWORD data_utf32[] = {0x6c49, 0x5b57};				// UTF-32編碼

             

            這里用BYTE、WORD、DWORD分別表示無符號8位整數,無符號16位整數和無符號32位整數。UTF-8、UTF-16、UTF-32分別以BYTE、WORD、DWORD作為編碼單位。

            “漢字”的UTF-8編碼需要6個字節。“漢字”的UTF-16編碼需要兩個WORD,大小是4個字節。“漢字”的UTF-32編碼需要兩個DWORD,大小是8個字節。4.2節會介紹將數字映射到UTF編碼的規則。

            3.4 作為字節流的字符(Character encoding scheme)

            字符編碼的第四層是計算機看到的字符,即在文件或內存中的字節流。例如,“字”的UTF-32編碼是0x5b57,如果用little endian表示,字節流是“57 5b 00 00”。如果用big endian表示,字節流是“00 00 5b 57”。

            字符編碼的第三層規定了一個字符由哪些編碼單位按什么順序表示。字符編碼的第四層在第三層的基礎上又考慮了編碼單位內部的字節序。UTF-8的編碼單位是字節,不受字節序的影響。UTF-16、UTF-32根據字節序的不同,又衍生出UTF-16LE、UTF-16BE、UTF-32LE、UTF-32BE四種編碼方案。LE和BE分別是Little Endian和Big Endian的縮寫。

            3.5 小結

            通過四層模型,我們又把字符編碼中發生的這些事情梳理了一遍。其實大多數代碼頁都不需要完整的四層模型,例如GB18030以字節為編碼單位,直接規定了字節序列和字符的映射關系,跳過了第二層,也不需要第四層。

            4 再談Unicode

            Unicode是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。Unicode用數字0-0x10FFFF來映射這些字符,最多可以容納1114112個字符,或者說有1114112個碼位。碼位就是可以分配給字符的數字。UTF-8、UTF-16、UTF-32都是將數字轉換到程序數據的編碼方案。

            Unicode字符集可以簡寫為UCS(Unicode Character Set)。早期的Unicode標準有UCS-2、UCS-4的說法。UCS-2用兩個字節編碼,UCS-4用4個字節編碼。UCS-4根據最高位為0的最高字節分成2^7=128個group。每個group再根據次高字節分為256個平面(plane)。每個平面根據第3個字節分為256行 (row),每行有256個碼位(cell)。group 0的平面0被稱作BMP(Basic Multilingual Plane)。將UCS-4的BMP去掉前面的兩個零字節就得到了UCS-2。

            Unicode標準計劃使用group 0 的17個平面: 從BMP(平面0)到平面16,即數字0-0x10FFFF?!墩務刄nicode編碼》主要介紹了BMP的編碼,本文將介紹完整的Unicode編碼,并從多個角度瀏覽Unicode。本文的介紹基于Unicode 5.0.0版本。

            4.1 瀏覽Unicode

            先看一些數字:每個平面有2^16=65536個碼位。Unicode計劃使用了17個平面,一共有17*65536=1114112個碼位。其實,現在已定義的碼位只有238605個,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16上只是定義了兩個各占65534個碼位的專用區(Private Use Area),分別是0xF0000-0xFFFFD和0x100000-0x10FFFD。所謂專用區,就是保留給大家放自定義字符的區域,可以簡寫為PUA。

            平面0也有一個專用區:0xE000-0xF8FF,有6400個碼位。平面0的0xD800-0xDFFF,共2048個碼位,是一個被稱作代理區(Surrogate)的特殊區域。它的用途將在4.2節介紹。

            238605-65534*2-6400-2408=99089。余下的99089個已定義碼位分布在平面0、平面1、平面2和平面14上,它們對應著Unicode目前定義的99089個字符,其中包括71226個漢字。平面0、平面1、平面2和平面14上分別定義了52080、3419、43253和337個字符。平面2的43253個字符都是漢字。平面0上定義了27973個漢字。

            在更深入地了解Unicode字符前,我們先了解一下UCD。

            4.1.1 什么是UCD

            UCD是Unicode字符數據庫(Unicode Character Database)的縮寫。UCD由一些描述Unicode字符屬性和內部關系的純文本或html文件組成。大家可以在Unicode組織的網站看到UCD的最新版本。

            UCD中的文本文件大都是適合于程序分析的Unicode相關數據。其中的html文件解釋了數據庫的組織,數據的格式和含義。UCD中最龐大的文件無疑就是描述漢字屬性的文件Unihan.txt。在UCD 5.0,0中,Unihan.txt文件大小有28,221K字節。Unihan.txt中包含了很多有參考價值的索引,例如漢字部首、筆劃、拼音、使用頻度、四角號碼排序等。這些索引都是基于一些比較權威的辭典,但大多數索引只能檢索部分漢字。

            我介紹UCD的目的主要是為了使用其中的兩個概念:Block和Script。

            4.1.2 Block

            UCD中的Blocks.txt將Unicode的碼位分割成一些連續的Block,并描述了每個Block的用途:

            開始碼位結束碼位Block名稱(英文)Block名稱(中文)
            0000007FBasic Latin基本拉丁字母
            008000FFLatin-1 Supplement拉丁字母補充-1
            0100017FLatin Extended-A拉丁字母擴充-A
            0180024FLatin Extended-B拉丁字母擴充-B
            025002AFIPA Extensions國際音標擴充
            02B002FFSpacing Modifier Letters進格修飾字符
            0300036FCombining Diacritical Marks組合附加符號
            037003FFGreek and Coptic希臘文和哥普特文
            040004FFCyrillic西里爾文
            0500052FCyrillic Supplement西里爾文補充
            0530058FArmenian亞美尼亞文
            059005FFHebrew希伯來文
            060006FFArabic基本阿拉伯文
            0700074FSyriac敘利亞文
            0750077FArabic Supplement阿拉伯文補充
            078007BFThaana塔納文
            07C007FFNKoN'Ko字母表
            0900097FDevanagari天成文書(梵文)
            098009FFBengali孟加拉文
            0A000A7FGurmukhi錫克教文
            0A800AFFGujarati古吉拉特文
            0B000B7FOriya奧里亞文
            0B800BFFTamil泰米爾文
            0C000C7FTelugu泰盧固文
            0C800CFFKannada卡納達文
            0D000D7FMalayalam德拉維族文
            0D800DFFSinhala僧伽羅文
            0E000E7FThai泰文
            0E800EFFLao老撾文
            0F000FFFTibetan藏文
            1000109FMyanmar緬甸文
            10A010FFGeorgian格魯吉亞文
            110011FFHangul Jamo朝鮮文
            1200137FEthiopic埃塞俄比亞文
            1380139FEthiopic Supplement埃塞俄比亞文補充
            13A013FFCherokee切羅基文
            1400167FUnified Canadian Aboriginal Syllabics加拿大印第安方言
            1680169FOgham歐甘文
            16A016FFRunic北歐古字
            1700171FTagalog塔加路文
            1720173FHanunoo哈努諾文
            1740175FBuhid布迪文
            1760177FTagbanwaTagbanwa文
            178017FFKhmer高棉文
            180018AFMongolian蒙古文
            1900194FLimbu林布文
            1950197FTai Le德宏傣文
            198019DFNew Tai Lue新傣文
            19E019FFKhmer Symbols高棉文
            1A001A1FBuginese布吉文
            1B001B7FBalinese巴厘文
            1D001D7FPhonetic Extensions拉丁字母音標擴充
            1D801DBFPhonetic Extensions Supplement拉丁字母音標擴充增補
            1DC01DFFCombining Diacritical Marks Supplement組合附加符號補充
            1E001EFFLatin Extended Additional拉丁字母擴充附加
            1F001FFFGreek Extended希臘文擴充
            2000206FGeneral Punctuation一般標點符號
            2070209FSuperscripts and Subscripts上標和下標
            20A020CFCurrency Symbols貨幣符號
            20D020FFCombining Diacritical Marks for Symbols符號用組合附加符號
            2100214FLetterlike Symbols似字母符號
            2150218FNumber Forms數字形式
            219021FFArrows箭頭符號
            220022FFMathematical Operators數學運算符號
            230023FFMiscellaneous Technical零雜技術用符號
            2400243FControl Pictures控制圖符
            2440245FOptical Character Recognition光學字符識別
            246024FFEnclosed Alphanumerics帶括號的字母數字
            2500257FBox Drawing制表符
            2580259FBlock Elements方塊元素
            25A025FFGeometric Shapes幾何形狀
            260026FFMiscellaneous Symbols零雜符號
            270027BFDingbats雜錦字型
            27C027EFMiscellaneous Mathematical Symbols-A零雜數學符號-A
            27F027FFSupplemental Arrows-A箭頭符號補充-A
            280028FFBraille Patterns盲文
            2900297FSupplemental Arrows-B箭頭符號補充-B
            298029FFMiscellaneous Mathematical Symbols-B零雜數學符號-B
            2A002AFFSupplemental Mathematical Operators數學運算符號
            2B002BFFMiscellaneous Symbols and Arrows零雜符號和箭頭
            2C002C5FGlagolitic格拉哥里字母表
            2C602C7FLatin Extended-C拉丁字母擴充-C
            2C802CFFCoptic科普特文
            2D002D2FGeorgian Supplement格魯吉亞文補充
            2D302D7FTifinagh提非納字母
            2D802DDFEthiopic Extended埃塞俄比亞文擴充
            2E002E7FSupplemental Punctuation標點符號補充
            2E802EFFCJK Radicals Supplement中日韓部首補充
            2F002FDFKangxi Radicals康熙字典部首
            2FF02FFFIdeographic Description Characters漢字結構描述字符
            3000303FCJK Symbols and Punctuation中日韓符號和標點
            3040309FHiragana平假名
            30A030FFKatakana片假名
            3100312FBopomofo注音符號
            3130318FHangul Compatibility Jamo朝鮮文兼容字母
            3190319FKanbun日文的漢字批注
            31A031BFBopomofo Extended注音符號擴充
            31C031EFCJK Strokes中日韓筆劃
            31F031FFKatakana Phonetic Extensions片假名音標擴充
            320032FFEnclosed CJK Letters and Months帶括號的中日韓字母及月份
            330033FFCJK Compatibility中日韓兼容字符
            34004DBFCJK Unified Ideographs Extension A中日韓統一表意文字擴充A
            4DC04DFFYijing Hexagram Symbols易經六十四卦象
            4E009FFFCJK Unified Ideographs中日韓統一表意文字
            A000A48FYi Syllables彝文音節
            A490A4CFYi Radicals彝文字根
            A700A71FModifier Tone Letters聲調修飾字母
            A720A7FFLatin Extended-D拉丁字母擴充-D
            A800A82FSyloti NagriSyloti Nagri字母表
            A840A87FPhags-paPhags-pa字母表
            AC00D7AFHangul Syllables朝鮮文音節
            D800DB7FHigh Surrogates高位替代
            DB80DBFFHigh Private Use Surrogates高位專用替代
            DC00DFFFLow Surrogates低位替代
            E000F8FFPrivate Use Area專用區
            F900FAFFCJK Compatibility Ideographs中日韓兼容表意文字
            FB00FB4FAlphabetic Presentation Forms字母變體顯現形式
            FB50FDFFArabic Presentation Forms-A阿拉伯文變體顯現形式-A
            FE00FE0FVariation Selectors字型變換選取器
            FE10FE1FVertical Forms豎排標點符號
            FE20FE2FCombining Half Marks組合半角標示
            FE30FE4FCJK Compatibility Forms中日韓兼容形式
            FE50FE6FSmall Form Variants小型變體形式
            FE70FEFFArabic Presentation Forms-B阿拉伯文變體顯現形式-B
            FF00FFEFHalfwidth and Fullwidth Forms半角及全角字符
            FFF0FFFFSpecials特殊區域
            100001007FLinear B Syllabary線形文字B音節文字
            10080100FFLinear B Ideograms線形文字B表意文字
            101001013FAegean Numbers愛琴海數字
            101401018FAncient Greek Numbers古希臘數字
            103001032FOld Italic古意大利文
            103301034FGothic哥特文
            103801039FUgaritic烏加里特楔形文字
            103A0103DFOld Persian古波斯文
            104001044FDeseret德塞雷特大學音標
            104501047FShavian肅伯納速記符號
            10480104AFOsmanyaOsmanya字母表
            108001083FCypriot Syllabary塞浦路斯音節文字
            109001091FPhoenician腓尼基文
            10A0010A5FKharoshthi迦婁士悌文
            12000123FFCuneiform楔形文字
            124001247FCuneiform Numbers and Punctuation楔形文字數字和標點
            1D0001D0FFByzantine Musical Symbols東正教音樂符號
            1D1001D1FFMusical Symbols音樂符號
            1D2001D24FAncient Greek Musical Notation古希臘音樂符號
            1D3001D35FTai Xuan Jing Symbols太玄經符號
            1D3601D37FCounting Rod Numerals算籌
            1D4001D7FFMathematical Alphanumeric Symbols數學用字母數字符號
            200002A6DFCJK Unified Ideographs Extension B中日韓統一表意文字擴充 B
            2F8002FA1FCJK Compatibility Ideographs Supplement中日韓兼容表意文字補充
            E0000E007FTags標簽
            E0100E01EFVariation Selectors Supplement字型變換選取器補充
            F0000FFFFFSupplementary Private Use Area-A補充專用區-A
            10000010FFFFSupplementary Private Use Area-B補充專用區-B

            Block是Unicode字符的一個屬性。屬于同一個Block的字符有著相近的用途。Block表中的開始碼位、結束碼位只是用來劃分出一塊區域,在開始碼位和結束碼位之間可能還有很多未定義的碼位。使用UniToy,大家可以按照Block瀏覽Unicode字符,既可以按列表顯示:

             

            也可以顯示每個字符的詳細信息:

            4.1.3 Script

            Unicode中每個字符都有一個Script屬性,這個屬性表明字符所屬的文字系統。Unicode目前支持以下Script:

            Script名稱(英文)Script名稱(中文)Script包含的字符數
            Arabic阿拉伯文966
            Armenian亞美尼亞文90
            Balinese巴厘文121
            Bengali孟加拉文91
            Bopomofo漢語注音符號64
            Braille盲文256
            Buginese布吉文30
            Buhid布迪文20
            Canadian Aboriginal加拿大印第安方言630
            Cherokee切羅基文85
            CommonCommon5020
            Coptic科普特文128
            Cuneiform楔形文字982
            Cypriot塞浦路斯音節文字55
            Cyrillic西里爾文277
            Deseret德塞雷特大學音標80
            Devanagari天成文書(梵文)107
            Ethiopic埃塞俄比亞文461
            Georgian格魯吉亞文120
            Gothic哥特文94
            Glagolitic格拉哥里字母表27
            Greek希臘文506
            Gujarati古吉拉特文83
            Gurmukhi錫克教文77
            Han漢文71570
            Hangul韓文書寫系統11619
            Hanunoo哈努諾文21
            Hebrew希伯來文133
            Hiragana平假名89
            InheritedInherited461
            Kannada卡納達文86
            Katakana片假名164
            Kharoshthi迦婁士悌文65
            Khmer高棉文146
            Lao老撾文65
            Latin拉丁文系1070
            Limbu林布文(尼泊爾東部)66
            Linear B線形文字B211
            Malayalam德拉維族文(印度)78
            Mongolian蒙古文152
            Myanmar緬甸文78
            New Tai Lue新傣文80
            NkoN'Ko字母表59
            Ogham歐甘文字29
            Old Italic古意大利文35
            Old Persian古波斯文50
            Oriya奧里亞文81
            OsmanyaOsmanya字母表40
            Phags PaPhags Pa字母表(蒙古)56
            Phoenician腓尼基文27
            Runic古代北歐文78
            Shavian肅伯納速記符號48
            Sinhala僧伽羅文80
            Syloti NagriSyloti Nagri字母表(印度)44
            Syriac敘利亞文77
            Tagalog塔加路文(菲律賓)20
            TagbanwaTagbanwa文(菲律賓)18
            Tai Le德宏傣文35
            Tamil泰米爾文71
            Telugu泰盧固文(印度)80
            Thaana馬爾代夫書寫體50
            Thai泰國文86
            Tibetan藏文195
            Tifinagh提非納字母表55
            Ugaritic烏加里特楔形文字31
            Yi彝文1220

            其中,有兩個Script值有著特殊的含義:

            • Common:Script屬性為Common的字符可能在多個文字系統中使用,不是某個文字系統特有的。例如:空格、數字等。
            • Inherited:Script屬性為Inherited的字符會繼承前一個字符的Script屬性。主要是一些組合用符號,例如:在“組合附加符號”區(0x300-0x36f),字符的Script屬性都是Inherited。

            UCD中的Script.txt列出了每個字符的Script屬性。使用UniToy可以按照Script屬性查看字符。例如:

            左側Script窗口中,第一層節點是按英文字母順序排列的Script屬性。第二層節點是包含該Script文字的行(row),點擊后顯示該行內屬于這個Script的字符。這樣,就可以集中查看屬于同一文字系統的字符。

            4.1.4 Unicode中的漢字

            前面提過,在Unicode已定義的99089個字符中,有71226個字符是漢字。它們的分布如下:

            Block名稱開始碼位結束碼位數量
            中日韓統一表意文字擴充A34004db56582
            中日韓統一表意文字4e009fbb20924
            中日韓兼容表意文字f900fa2d302
            中日韓兼容表意文字fa30fa6a59
            中日韓兼容表意文字fa70fad9106
            中日韓統一表意文字擴充B200002a6d642711
            中日韓兼容表意文字補充2f8002fa1d542

            UCD的Unihan.txt中的部首偏旁索引(kRSUnicode)可以檢索全部71226個漢字。kRSUnicode的部首是按照康熙字典定義的,共214個部首。簡體字按照簡體部首對應的繁體部首檢索。UniToy整理了康熙字典部首對應的簡體部首,提供了按照部首檢索漢字的功能:

            4.2 UTF編碼

            在字符編碼的四個層次中,第一層的范圍和第二層的編碼在4.1節已經詳細討論過了。本節討論第三層的UTF編碼和第四層的字節序,主要談談第三層的UTF編碼,即怎樣將Unicode定義的編碼轉換成程序數據。

            4.2.1 UTF-8

            UTF-8以字節為單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:

            Unicode編碼(16進制)UTF-8 字節流(二進制)
            000000 - 00007F0xxxxxxx
            000080 - 0007FF110xxxxx 10xxxxxx
            000800 - 00FFFF1110xxxx 10xxxxxx 10xxxxxx
            010000 - 10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

            UTF-8的特點是對不同范圍的字符使用不同長度的編碼。對于0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個字節。從上表可以看出,4字節模板有21個x,即可以容納21位二進制數字。Unicode的最大碼位0x10FFFF也只有21位。

            例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

            例2:“”字的Unicode編碼是0x20C30。0x20C30在0x010000-0x10FFFF之間,使用用4字節模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。將0x20C30寫成21位二進制數字(不足21位就在前面補0):0 0010 0000 1100 0011 0000,用這個比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。

            4.2.2 UTF-16

            UniToy有個“輸出編碼”功能,可以輸出當前選擇的文本編碼。因為UniToy內部采用UTF-16編碼,所以輸出的編碼就是文本的UTF-16編碼。例如:如果我們輸出“漢”字的UTF-16編碼,可以看到0x6C49,這與“漢”字的Unicode編碼是一致的。如果我們輸出“”字的UTF-16編碼,可以看到0xD843, 0xDC30。“”字的Unicode編碼是0x20C30,它的UTF-16編碼是怎樣得到的呢?

            4.2.2.1 編碼規則

            UTF-16編碼以16位無符號整數為單位。我們把Unicode編碼記作U。編碼規則如下:

            • 如果U<0x10000,U的UTF-16編碼就是U對應的16位無符號整數(為書寫簡便,下文將16位無符號整數記作WORD)。
            • 如果U≥0x10000,我們先計算U'=U-0x10000,然后將U'寫成二進制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16編碼(二進制)就是:110110yyyyyyyyyy110111xxxxxxxxxx。

            為什么U'可以被寫成20個二進制位?Unicode的最大碼位是0x10ffff,減去0x10000后,U'的最大值是0xfffff,所以肯定可以用20個二進制位表示。例如:“”字的Unicode編碼是0x20C30,減去0x10000后,得到0x10C30,寫成二進制是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:1101100001000011 1101110000110000,即0xD843 0xDC30。

            4.2.2.2 代理區(Surrogate)

            按照上述規則,Unicode編碼0x10000-0x10FFFF的UTF-16編碼有兩個WORD,第一個WORD的高6位是110110,第二個WORD的高6位是110111。可見,第一個WORD的取值范圍(二進制)是11011000 00000000到11011011 11111111,即0xD800-0xDBFF。第二個WORD的取值范圍(二進制)是11011100 00000000到11011111 11111111,即0xDC00-0xDFFF。

            為了將一個WORD的UTF-16編碼與兩個WORD的UTF-16編碼區分開來,Unicode編碼的設計者將0xD800-0xDFFF保留下來,并稱為代理區(Surrogate):

            D800DB7FHigh Surrogates高位替代
            DB80DBFFHigh Private Use Surrogates高位專用替代
            DC00DFFFLow Surrogates低位替代

            高位替代就是指這個范圍的碼位是兩個WORD的UTF-16編碼的第一個WORD。低位替代就是指這個范圍的碼位是兩個WORD的UTF-16編碼的第二個WORD。那么,高位專用替代是什么意思?我們來解答這個問題,順便看看怎么由UTF-16編碼推導Unicode編碼。

            解:如果一個字符的UTF-16編碼的第一個WORD在0xDB80到0xDBFF之間,那么它的Unicode編碼在什么范圍內?我們知道第二個WORD的取值范圍是0xDC00-0xDFFF,所以這個字符的UTF-16編碼范圍應該是0xDB80 0xDC00到0xDBFF 0xDFFF。我們將這個范圍寫成二進制:

            1101101110000000 11011100 00000000 - 1101101111111111 1101111111111111

            按照編碼的相反步驟,取出高低WORD的后10位,并拼在一起,得到

            1110 0000 0000 0000 0000 - 1111 1111 1111 1111 1111

            即0xe0000-0xfffff,按照編碼的相反步驟再加上0x10000,得到0xf0000-0x10ffff。這就是UTF-16編碼的第一個WORD在0xdb80到0xdbff之間的Unicode編碼范圍,即平面15和平面16。因為Unicode標準將平面15和平面16都作為專用區,所以0xDB80到0xDBFF之間的保留碼位被稱作高位專用替代。

            4.2.3 UTF-32

            UTF-32編碼以32位無符號整數為單位。Unicode的UTF-32編碼就是其對應的32位無符號整數。

            4.2.4 字節序

            根據字節序的不同,UTF-16可以被實現為UTF-16LE或UTF-16BE,UTF-32可以被實現為UTF-32LE或UTF-32BE。例如:

            字符Unicode編碼UTF-16LEUTF-16BEUTF32-LEUTF32-BE
            0x6C4949 6C6C 4949 6C 00 0000 00 6C 49
            0x20C3043 D8 30 DCD8 43 DC 3030 0C 02 0000 02 0C 30

             

            那么,怎么判斷字節流的字節序呢?

             

            Unicode標準建議用BOM(Byte Order Mark)來區分字節序,即在傳輸字節流前,先傳輸被作為BOM的字符"零寬無中斷空格"。這個字符的編碼是FEFF,而反過來的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定義的碼位,不應該出現在實際傳輸中。下表是各種UTF編碼的BOM:

            UTF編碼Byte Order Mark
            UTF-8EF BB BF
            UTF-16LEFF FE
            UTF-16BEFE FF
            UTF-32LEFF FE 00 00
            UTF-32BE00 00 FE FF

            5 結束語

            程序員的工作就是將復雜的世界簡單地表達出來,希望這篇文章也能做到這一點。本文的初稿完成于2007年2月14日。我會在我的個人主頁http://www.fmddlmyy.cn維護這篇文章的最新版本。

            posted @ 2011-05-12 21:58 RTY 閱讀(504) | 評論 (0)編輯 收藏

            我曾經寫過一篇《談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞》(以下簡稱《談談Unicode編碼》),在網上流傳較廣,我也收到不少朋友的反饋。本文探討《談談Unicode編碼》中未介紹或介紹較少的代碼頁、Surrogates等問題,補充一些Unicode資料,順帶介紹一下我最近編寫的一個Unicode工具:UniToy。本文雖然是前文的補充,但在寫作上盡量做到獨立成篇。

            標題中的“淺談”是對自己的要求,我希望文字能盡量淺顯易懂。但本文還是假設讀者知道字節、16進制,了解《談談Unicode編碼》中介紹過的字節序和Unicode的基本概念。

            0 UniToy

            UniToy是我編寫的一個小工具。通過UniToy,我們可以全方位、多角度地查看Unicode,了解Unicode和語言、代碼頁的關系,完成一些文字編碼的相關工作。本文的一些內容是通過UniToy演示的。大家可以從我的網站(www.fmddlmyy.cn)下載UniToy的演示版本

            1 文字的顯示

            1.1 發生了什么?

            我們首先以Windows為例來看看文字顯示過程中發生了什么。用記事本打開一個文本文件,可以看到文件包含的文字:

            字符和編碼

            如果我們用UltraEdit或Hex Workshop查看這個文件的16進制數據,可以看到:

            D7D6 B7FB BACD B1E0 C2EB

            我們看到:文件“例子GBK.txt”有10個字節,依次是“D7 D6 B7 FB BA CD B1 E0 C2 EB”,這就是記事本從文件中讀到的內容。記事本是用來打開文本文件的,所以它會調用Windows的文本顯示函數將讀到的數據作為文本顯示。Windows首先將文本數據轉換到它內部使用的編碼格式:Unicode,然后按照文本的Unicode去字體文件中查找字體圖像,最后將圖像顯示到窗口上。 總結一下前面的分析,文字的顯示應該是這樣的:

            • 步驟1:文字首先以某種編碼保存在文件中。
            • 步驟2:Windows將文件中的文字編碼映射到Unicode。
            • 步驟3:Windows按照Unicode在字體文件中查找字體圖像,畫到窗口上。
            所謂編碼就是用數字表示字符,例如用D7D6表示“字”。當然,編碼還意味著約定,即大家都認可。從《談談Unicode編碼》中,我們知道Unicode也是一種文字編碼,它的特殊性在于它是由國際組織設計,可以容納全世界所有語言文字。而我們平常使用的文字編碼通常是針對一個區域的語言、文字設計,只支持特定的語言文字。例如:在上面的例子中,文件“例子GBK.txt”采用的就是GBK編碼。

             

            如果上述3個步驟中任何一步發生了錯誤,文字就不能被正確顯示,例如:

            • 錯誤1:如果弄錯了編碼,例如將Big5編碼的文字當作GBK編碼,就會出現亂碼。

            • 錯誤2:如果從特定編碼到Unicode的映射發生錯誤,例如文本數據中出現該編碼方案未定義的字符,Windows就會使用缺省字符,通常是?。

            • 如果當前字體不支持要顯示的字符,Windows就會顯示字體文件中的缺省圖像:空白或方格。

            在Unicode被廣泛使用前,有多少種語言、文字,就可能有多少種文字編碼方案。一種文字也可能有多種編碼方案。那么我們怎么確定文本數據采用了什么編碼?

            1.2 采用了哪種編碼?

            按照慣例,文本文件中的數據都是文本編碼,那么它怎么表明自己的編碼格式?在記事本的“打開”對話框上:

            我們可以看到記事本支持4種編碼格式:ANSI、Unicode、Unicode big endian、UTF-8。如果讀者看過《談談Unicode編碼》,對Unicode、Unicode big endian、UTF-8應該不會陌生,其實它們更準確的名稱應該是UTF-16LE(Little Endian)、UTF-16BE(Big Endian)和UTF-8,它們是基于Unicode的不同編碼方案。

            在《談談Unicode編碼》中介紹過,Windows通過在文本文件開頭增加一些特殊字節(BOM)來區分上述3種編碼,并將沒有BOM的文本數據按照ANSI代碼頁處理。那么什么是代碼頁,什么是ANSI代碼頁?

            2 代碼頁和字符集

            2.1 Windows的代碼頁

            2.1.1 代碼頁

            代碼頁(Code Page)是個古老的專業術語,據說是IBM公司首先使用的。代碼頁和字符集的含義基本相同,代碼頁規定了適用于特定地區的字符集合,和這些字符的編碼。可以將代碼頁理解為字符和字節數據的映射表。

            Windows為自己支持的代碼頁都編了一個號碼。例如代碼頁936就是簡體中文 GBK,代碼頁950就是繁體中文 Big5。代碼頁的概念比較簡單,就是一個字符編碼方案。但要說清楚Windows的ANSI代碼頁,就要從Windows的區域(Locale)說起了。

            2.1.2 區域和ANSI代碼頁

            微軟為了適應世界上不同地區用戶的文化背景和生活習慣,在Windows中設計了區域(Locale)設置的功能。Local是指特定于某個國家或地區的一組設定,包括代碼頁,數字、貨幣、時間和日期的格式等。在Windows內部,其實有兩個Locale設置:系統Locale和用戶Locale。系統Locale決定代碼頁,用戶Locale決定數字、貨幣、時間和日期的格式。我們可以在控制面板的“區域和語言選項”中設置系統Locale和用戶Locale:

            每個Locale都有一個對應的代碼頁。Locale和代碼頁的對應關系,大家可以參閱我的另一篇文章《談談Windows程序中的字符編碼》的附錄1。系統Locale對應的代碼頁被作為Windows的默認代碼頁。在沒有文本編碼信息時,Windows按照默認代碼頁的編碼方案解釋文本數據。這個默認代碼頁通常被稱作ANSI代碼頁(ACP)。

            ANSI代碼頁還有一層意思,就是微軟自己定義的代碼頁。在歷史上,IBM的個人計算機和微軟公司的操作系統曾經是PC的標準配置。微軟公司將IBM公司定義的代碼頁稱作OEM代碼頁,在IBM公司的代碼頁基礎上作了些增補后,作為自己的代碼頁,并冠以ANSI的字樣。我們在“區域和語言選項”高級頁面的代碼頁轉換表中看到的包含ANSI字樣的代碼頁都是微軟自己定義的代碼頁。例如:

            • 874 (ANSI/OEM - 泰文)
            • 932 (ANSI/OEM - 日文 Shift-JIS)
            • 936 (ANSI/OEM - 簡體中文 GBK)
            • 949 (ANSI/OEM - 韓文)
            • 950 (ANSI/OEM - 繁體中文 Big5)
            • 1250 (ANSI - 中歐)
            • 1251 (ANSI - 西里爾文)
            • 1252 (ANSI - 拉丁文 I)
            • 1253 (ANSI - 希臘文)
            • 1254 (ANSI - 土耳其文)
            • 1255 (ANSI - 希伯來文)
            • 1256 (ANSI - 阿拉伯文)
            • 1257 (ANSI - 波羅的海文)
            • 1258 (ANSI/OEM - 越南)

            在UniToy中,我們可以按照代碼頁編碼順序查看這些代碼頁的字符和編碼:

            我們不能直接設置ANSI代碼頁,只能通過選擇系統Locale,間接改變當前的ANSI代碼頁。微軟定義的Locale只使用自己定義的代碼頁。所以,我們雖然可以通過“區域和語言選項”中的代碼頁轉換表安裝很多代碼頁,但只能將微軟的代碼頁作為系統默認代碼頁。

            2.1.3 代碼頁轉換表

            在Windows 2000以后,Windows統一采用UTF-16作為內部字符編碼?,F在,安裝一個代碼頁就是安裝一張代碼頁轉換表。通過代碼頁轉換表,Windows既可以將代碼頁的編碼轉換到UTF-16,也可以將UTF-16轉換到代碼頁的編碼。代碼頁轉換表的具體實現可以是一個以nls為后綴的數據文件,也可以是一個提供轉換函數的動態鏈接庫。有的代碼頁是不需要安裝的。例如:Windows將UTF-7和UTF-8分別作為代碼頁65000和代碼頁65001。UTF-7、UTF-8和UTF-16都是基于Unicode的編碼方案。它們之間可以通過簡單的算法直接轉換,不需要安裝代碼頁轉換表。

            在安裝過一個代碼頁后,Windows就知道怎樣將該代碼頁的文本轉換到Unicode文本,也知道怎樣將Unicode文本轉換成該代碼頁的文本。例如:UniToy有導入和導出功能。所謂導入功能就是將任一代碼頁的文本文件轉換到Unicode文本;導出功能就是將Unicode文本轉換到任一指定的代碼頁。這里所說的代碼頁就是指系統已安裝的代碼頁:

            其實,如果全世界人民在計算機剛發明時就統一采用Unicode作為字符編碼,那么代碼頁就沒有存在的必要了。可惜在Unicode被發明前,世界各國人民都發明并使用了各種字符編碼方案。所以,Windows必須通過代碼頁支持已經被廣泛使用的字符編碼。從這種意義看,代碼頁主要是為了兼容現有的數據、程序和習慣而存在的。

            2.1.4 SBCS、DBCS和MBCS

            SBCS、DBCS和MBCS分別是單字節字符集、雙字節字符集和多字節字符集的縮寫。SBCS、DBCS和MBCS的最大編碼長度分別是1字節、兩字節和大于兩字節(例如4或5字節)。例如:代碼頁1252 (ANSI-拉丁文 I)是單字節字符集;代碼頁936 (ANSI/OEM-簡體中文 GBK)是雙字節字符集;代碼頁54936 (GB18030 簡體中文)是多字節字符集。

            單字節字符集中的字符都用一個字節表示。顯然,SBCS最多只能容納256個字符。

            雙字節字符集的字符用一個或兩個字節表示。那么我們從文本數據中讀到一個字節時,怎么判斷它是單字節字符,還是雙字節字符的首字符?答案是通過字節所處范圍來判斷。例如:在GBK編碼中,單字節字符的范圍是0x00-0x80,雙字節字符首字節的范圍是0x81到0xFE。我們順序讀取字節數據,如果讀到的字節在0x81到0xFE內,那么這個字節就是雙字節字符的首字節。GBK定義雙字節字符的尾字節范圍是0x40到0x7E和0x80到0xFE。

            GB18030是多字節字符集,它的字符可以用一個、兩個或四個字節表示。這時我們又如何判斷一個字節是屬于單字節字符,雙字節字符,還是四字節字符?GB18030與GBK是兼容的,它利用了GBK雙字節字符尾字節的未使用碼位。GB18030的四字節字符的第一字節的范圍也是0x81到0xFE,第二字節的范圍是0x30-0x39。通過第二字節所處范圍就可以區分雙字節字符和四字節字符。GB18030定義四字節字符的第三字節范圍是0x81到0xFE,第四字節范圍是0x30-0x39。

            2.2 代碼頁實例

            2.2.1 實例一:GB18030代碼頁

            1.1節的“錯誤2”中演示了一個全被顯示成'?'的文件。這個文件的數據是:

            其實,這是一個包含了6個四字節字符的GB18030編碼的文件。記事本按照GBK顯示這些數據,而GB18030的四字節字符編碼在GBK中是未定義的。Windows根據首字節范圍判斷出12個雙字節字符,然后因為找不到匹配的轉換而將其映射到默認字符'?'。使用UniToy按照GB18030代碼頁導入這個文件,就可以看到:

            這個GB18030編碼的文件是用UniToy創建的,編輯Unicode文本,然后導出到GB18030編碼格式。

            2.2.2 實例二:GBK和Big5的轉換

            綜合使用UniToy的導入、導出功能就可以在任意兩個代碼頁之間轉換文本。其實,由于各代碼頁支持的字符范圍不同,我們一般不會直接在代碼頁間轉換文本。例如將以下GBK編碼的文本:

            直接轉換到Big5編碼,就會看到:

            變成'?'的字符都是Big5編碼不支持的簡化字。在從Unicode轉換到Big5編碼時,由于Big5編碼不支持這些字符,Windows就用默認字符'?'代替。在UniToy中,我們可以先將簡體字轉換到繁體字,然后再導出到Big5編碼,就可以正常顯示:

            同理,將Big5編碼的文本轉換到GBK編碼的步驟應該是:

            • 將Big5編碼的文本導入到Unicode文本;
            • 將繁體的Unicode文本轉換簡體的Unicode文本;
            • 將簡體的Unicode文本導出到GBK文本。

            2.3 互聯網的字符集

            2.3.1 字符集

            互聯網上的信息繽紛多彩,但文本依然是最重要的信息載體。html文件通過標記表明自己使用的字符集。例如:

            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

            或者:

            <meta http-equiv="charset" content="iso-8859-1">

            那么我們可以使用哪些字符集(charset)呢?在IETF(互聯網工程任務組)的網頁上維護著一份可以在互聯網上使用的字符集的清單:CHARACTER SETS。如果有新的字符集被登記,IETF會更新這份文檔。

            簡單瀏覽一下,2006年12月7日的版本列出了253個字符集。其中也包括微軟的CP1250 ~ CP1258,在這里它們不會被稱作什么ANSI代碼頁,而是被簡單地稱作windows-1250、windows-1251等。其實在Unicode被廣泛使用前,除了中日韓等大字符集,世界上,特別是西方使用最廣泛的字符集應該是ISO 8859系列字符集。

            2.3.2 ISO 8859系列字符集

            ISO 8859系列字符集是歐洲計算機制造商協會(ECMA)在上世紀80年代中期設計,并被國際標準化(ISO)組織采納為國際標準。ISO 8859系列字符集目前有15個字符集,包括:

            • ISO 8859-1 大部分的西歐語系,例如英文、法文、西班牙文和德文等(Latin-1)
            • ISO 8859-2 大部分的中歐和東歐語系,例如捷克文、波蘭文和匈牙利文等(Latin-2)
            • ISO 8859-3 歐洲東南部和其它各種文字(Latin-3)
            • ISO 8859-4 斯堪的那維亞和波羅的海語系(Latin-4)
            • ISO 8859-5 拉丁文與斯拉夫文(俄文、保加利亞文等)
            • ISO 8859-6 拉丁文與阿拉伯文
            • ISO 8859-7 拉丁文與希臘文
            • ISO 8859-8 拉丁文與希伯來文
            • ISO 8859-9 為土耳其文修正的Latin-1(Latin-5)
            • ISO 8859-10 拉普人、北歐與愛斯基摩人的文字(Latin-6)
            • ISO 8859-11 拉丁文與泰文
            • ISO 8859-13 波羅的海周邊語系,例如拉脫維亞文等(Latin-7)
            • ISO 8859-14 凱爾特文,例如蓋爾文、威爾士文等(Latin-8)
            • ISO 8859-15 改進的Latin-1,增加遺漏的法文、芬蘭文字符和歐元符號(Latin-9)
            • ISO 8859-16 羅馬尼亞文(Latin-10)

            其中缺少的編號12據說是為了預留給天城體梵文字母(Deva-nagari)的。印地文和尼泊爾文都使用了這種在七世紀形成的字母表。由于印度定義了自己的編碼ISCII(Indian Script Code for Information Interchange),所以這個編號就未被使用。ISO 8859系列字符集都是單字節字符集,即只使用0x00-0xFF對字符編碼。

            大家都知道ASCII吧,那么大家知道ANSI X3.4和ISO 646嗎?在1968年發布的ANSI X3.4和1972年發布的ISO 646就是ASCII編碼,只不過是不同組織發布的。絕大多數字符集都與ASCII編碼保持兼容,ISO 8859系列字符集也不例外,它們的0x00-0x7f都與ASCII碼保持一致,各字符集的不同之處在于如何利用0x80-0xff的碼位。使用UniToy可以查看ISO 8859系列所有字符集的編碼,例如:

            通過這些演示,大家是不是覺得代碼頁和字符集都是很簡單、樸實的東西呢?好,在進入Unicode的話題前,讓我們先看一個很深奧的概念。

            posted @ 2011-05-12 21:56 RTY 閱讀(769) | 評論 (0)編輯 收藏

                 摘要: 字符集編碼與 C/C++ 源文件字符編譯亂彈 2010年2月24日Breaker原創發表評論閱讀評論 最近在看國際化編程 (i18n: internationalization) 的東西,也弄清楚了點字符集有關的一些問題,其實網上的一些牛人已經將字符集、Unicode 等相關的問題說的很清楚了,我在這里引用他們的總結并自己小結一下心得,并且實驗一下在編譯時,源代碼自身的字...  閱讀全文

            posted @ 2011-05-12 21:40 RTY 閱讀(2274) | 評論 (4)編輯 收藏

            僅列出標題
            共31頁: First 20 21 22 23 24 25 26 27 28 Last 
            久久人人爽人人爽人人片av高请| 精品久久久中文字幕人妻 | 久久久久国产精品| 亚洲AV无码成人网站久久精品大| 亚洲国产婷婷香蕉久久久久久| 亚洲午夜久久影院| 精品久久久久久国产牛牛app| 欧美精品一区二区精品久久| 国内精品伊人久久久久AV影院| 亚洲精品美女久久久久99| 无码国内精品久久人妻蜜桃 | 99久久精品费精品国产 | 99久久亚洲综合精品成人| 日韩一区二区久久久久久| 久久精品国产免费一区| 久久久亚洲精品蜜桃臀| 一本久久综合亚洲鲁鲁五月天| 久久综合亚洲色HEZYO社区 | 成人免费网站久久久| 久久99国产亚洲高清观看首页| 99久久亚洲综合精品网站| 无码8090精品久久一区| 国产毛片欧美毛片久久久| 久久国产乱子伦免费精品| 99久久精品国产一区二区蜜芽| 久久精品视频91| 亚洲AV无码成人网站久久精品大| 97精品久久天干天天天按摩| 国产亚洲色婷婷久久99精品91| 人人妻久久人人澡人人爽人人精品| 久久亚洲春色中文字幕久久久| 久久青青草原精品影院| 亚洲国产高清精品线久久| 久久99国产精品尤物| 久久一区二区三区免费| 人妻无码αv中文字幕久久 | 看久久久久久a级毛片| 国产精品亚洲综合专区片高清久久久 | 久久精品国产亚洲AV大全| 久久人人爽人人爽人人片AV麻豆| 中文字幕乱码久久午夜|