青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

大龍的博客

常用鏈接

統(tǒng)計(jì)

最新評(píng)論

談?wù)刉indows程序中的字符編碼 ----- 轉(zhuǎn)

    寫這篇文章的起因是這么一個(gè)問(wèn)題:我們在使用和安裝Windows程序時(shí),有時(shí)會(huì)看到以“2052”、“1033”這些數(shù)字為名的文件夾,這些數(shù)字似乎和字符集有關(guān),但它們究竟是什么意思呢?

  研究這個(gè)問(wèn)題的同時(shí),又會(huì)遇到其它問(wèn)題。我們會(huì)談到Windows的內(nèi)部架構(gòu)、Win32 API的A/W函數(shù)、Locale、ANSI代碼頁(yè)、與字符編碼有關(guān)的編譯參數(shù)、MBCS和Unicode程序、資源和亂碼等,一起經(jīng)歷這段瑣碎細(xì)節(jié)為主,間或樂(lè)趣點(diǎn)綴的旅程。

0 Where is Win32 API


    Windows程序有用戶態(tài)和核心態(tài)的說(shuō)法。在32位地址空間中,0x80000000以下屬于用戶態(tài),0x80000000以上屬于核心態(tài)。所有硬件管理都在核心態(tài)。用戶態(tài)程序的不能直接使用核心態(tài)的任何代碼。所謂核心態(tài)其實(shí)只是CPU的一種保護(hù)模式。在x86 CPU上,用戶態(tài)處于ring 3,核心態(tài)處于ring 0。

    從用戶態(tài)進(jìn)入核心態(tài)的最常用的方法是在寄存器eax填一個(gè)功能碼,然后執(zhí)行int 2e。這有點(diǎn)像DOS時(shí)代的DOS和BIOS系統(tǒng)調(diào)用。在NT架構(gòu)中這種機(jī)制被稱作system service。

    在核心態(tài)提供system service的有兩個(gè)家伙:ntoskrnl.exe和win32k.sys。ntoskrnl.exe是Windows的大腦,它的上層被稱為Executive,下層被稱作Kernel。Win32k.sys提供與顯示有關(guān)的system service。

    在用戶態(tài)一側(cè),有一個(gè)重要的角色叫作ntdll.dll,大多數(shù)system service都是它調(diào)用的。它封裝這些system service,然后提供一個(gè)API接口。這個(gè)接口被稱作native API。 native API的用戶是各個(gè)子系統(tǒng)(subsystem),包括Win32子系統(tǒng)、OS/2子系統(tǒng)、POSIX子系統(tǒng)。各個(gè)子系統(tǒng)為Win32、OS2、POSIX程序提供了運(yùn)行平臺(tái)。

    ntdll.dll由于提供了平臺(tái)無(wú)關(guān)的API接口,所以被看作是NT系統(tǒng)的原生接口,由之得到了“native API”的匪號(hào)。其實(shí)它的主要工作是將調(diào)用傳遞到核心態(tài)。

    Win32、OS/2、POSIX,聽起來(lái)很龐大。其實(shí)真正做好的只有Win32子系統(tǒng)。OS2、POSIX都是Console UI,即只有字符界面。提供OS/2子系統(tǒng),只因?yàn)樵?988年,NT的主要設(shè)計(jì)目標(biāo)就是與OS/2兼容,后來(lái)由于Windows 3.0賣得很好,所以設(shè)計(jì)目標(biāo)被變更為與Windows兼容。提供POSIX子系統(tǒng),是為了應(yīng)付美國(guó)政府的一個(gè)編號(hào)為FIPS 151-2的標(biāo)準(zhǔn)。

    Win32子系統(tǒng)的管理員是一個(gè)叫作csrss.exe的弟兄,它的全名是:Client/Server Run-Time Subsystem。它剛上任時(shí),本來(lái)要分管所有的子系統(tǒng),但后來(lái)POSIX和OS/2都被分別處理了,所以只管了一個(gè)Win32。即使這樣也很了不起,所有的Win32程序的進(jìn)程、線程們都要向它登記。

    不過(guò)Win32程序用得最多的還是Win32子系統(tǒng)的DLL們,最核心的DLL包括:kernel32.dll、User32.dll、Gdi32.dll、Advapi32.dll。這些DLL包裝了ntdll.dll的native API。其中Gdi32.dll比較特殊,它與核心態(tài)的win32k.sys直接保持聯(lián)系,以提高NT系統(tǒng)的圖形處理能力。Win32子系統(tǒng)的DLL們提供的接口函數(shù)在MSDN文檔中被詳細(xì)介紹,它們就是Win32 API。

附錄0 Windows的啟動(dòng)


    計(jì)算機(jī)上電后,從BIOS的ROM開始運(yùn)行。BIOS在做一些初始化后會(huì)將硬盤的第一個(gè)扇區(qū)的數(shù)據(jù)讀入內(nèi)存,然后將控制權(quán)交給它,這段數(shù)據(jù)被稱作Master Boot Record(MBR)。

    MBR包含一段啟動(dòng)代碼和硬盤的主分區(qū)表。這段啟動(dòng)代碼掃描主分區(qū)表,找到第一個(gè)可以啟動(dòng)的分區(qū),然后將這個(gè)分區(qū)的第一個(gè)扇區(qū)讀入內(nèi)存并運(yùn)行。這個(gè)扇區(qū)被稱作引導(dǎo)扇區(qū)(boot sector)。

    引導(dǎo)扇區(qū)的代碼具備讀文件系統(tǒng)根目錄的能力,顯然不同的文件系統(tǒng)需要不同的代碼。引導(dǎo)扇區(qū)會(huì)從根目錄中讀出一個(gè)叫作ntldr的文件。顧名思義,這個(gè)文件是load NT的主要角色。它的業(yè)績(jī)主要包括將CPU從實(shí)模式轉(zhuǎn)入保護(hù)模式,啟動(dòng)分頁(yè)機(jī)制,處理boot.ini等。

    如果boot.ini中有一句:

C:\bootsect.rh="Red Hat Linux"

    bootsect.rh的內(nèi)容是Linux引導(dǎo)扇區(qū),用戶又選擇了“Red Hat Linux”,ntldr就會(huì)將執(zhí)行Linux的引導(dǎo)扇區(qū),開始Linux的引導(dǎo)。如果用戶選擇繼續(xù)使用Windows,ntldr會(huì)裝載并運(yùn)行我們前面提到的ntoskrnl.exe。

    ntoskrnl.exe會(huì)啟動(dòng)會(huì)話管理器smss.exe。smss.exe啟動(dòng)csrss.exe和winlogon.exe。smss.exe會(huì)永遠(yuǎn)等待csrss.exe和winlogon.exe返回。如果兩者之一異常中止,就會(huì)導(dǎo)致系統(tǒng)崩潰。所以病毒們經(jīng)常以打擊csrss.exe為樂(lè)。

    winlogon.exe負(fù)責(zé)用戶登錄,在完成登錄后,它會(huì)啟動(dòng)注冊(cè)表HKLM\SOFTWARE\Microsoft\Windows NT\Current Version\Winlogon項(xiàng)下Userinit值指定的程序。該值的缺省數(shù)據(jù)是userinit.exe。userinit.exe會(huì)裝載個(gè)人設(shè)置,讓硬盤響個(gè)不停,并考驗(yàn)我們的耐性,最后啟動(dòng)注冊(cè)表同一項(xiàng)下Shell值指定的程序。該值的缺省數(shù)據(jù)是Explorer.exe。Explorer.exe運(yùn)行后,我們就會(huì)看到熟悉的開始菜單和桌面。

 

 

    要了解Win32子系統(tǒng)的DLL們提供了哪些API,最直接的方法就是用Win32dsm直接查看DLL們的導(dǎo)出表。這時(shí)我們會(huì)發(fā)現(xiàn)Win32 API中帶字符串的API一般都有兩個(gè)版本,例如CreateFileA和CreateFileW。當(dāng)然也有例外,例如GetProcAddress函數(shù)。

 

    A代表ANSI代碼頁(yè),W是寬字符,即Unicode字符。Windows中的Unicode字符一般指UCS2的UTF16-LE編碼。讓我們通過(guò)幾個(gè)實(shí)例觀察A/W版本間的關(guān)系。

    例1:用WIn32dsm查看gdi32.dll的匯編代碼,可以看到TextOutA調(diào)用GdiGetCodePage獲取當(dāng)前代碼頁(yè),再調(diào)用MultiByteToWideChar轉(zhuǎn)換輸入的字符串,然后調(diào)用一個(gè)內(nèi)部函數(shù)。而TextOutW直接調(diào)用這個(gè)內(nèi)部函數(shù)。

    例2:用調(diào)試器跟蹤一個(gè)使用了CreateFileA的程序,可以看到:CreateFileA在將輸入字符串轉(zhuǎn)換為Unicode后,會(huì)調(diào)用CreateFileW。假設(shè)輸入文件名是“測(cè)試.txt”,對(duì)應(yīng)的數(shù)據(jù)就是:“B2 E2 CA D4 2E 74 78 74 00”。在調(diào)試器中可以看到傳給CreateFileW的文件名數(shù)據(jù)是:“4B 6D D5 8B 2E 00 74 00 78 00 74 00 00 00”。 這是"測(cè)試.txt"對(duì)應(yīng)的Unicdoe字符串。CreateFileW會(huì)接著調(diào)用ntdll.dll中的NtCreateFile。順便看看NtCreateFile的代碼:
mov eax, 00000020
lea edx, dword ptr [esp+04]
int 2E
ret 002C
可見這個(gè)native API只是簡(jiǎn)單地調(diào)用了核心態(tài)提供的0x20號(hào)system service。

    例3:gdi32.dll中的GetGlyphOutline函數(shù)可以獲取指定字符的字模。GetGlyphOutlineA和GetGlyphOutlineW函數(shù)都會(huì)調(diào)用同一個(gè)內(nèi)部函數(shù)(記作F)。函數(shù)F在返回前將通過(guò)int 2E調(diào)用0x10B1號(hào)system service。
GetGlyphOutlineW直接調(diào)用函數(shù)F。GetGlyphOutlineA在調(diào)用函數(shù)F前,要依次調(diào)用GdiGetCodePage、IsDBCSLeadByteEx和MultiByteToWideChar,將當(dāng)前代碼頁(yè)的字符編碼轉(zhuǎn)換成Unicode編碼。
如果我們調(diào)用GetGlyphOutlineA時(shí)傳入“baba”,這是“漢”字的GBK編碼,用調(diào)試器可以看到傳給函數(shù)F的字符編碼是“6c49”,這是“漢”字的Unicode編碼。

    從以上例子可見,A版本總會(huì)在某處將輸入的字符串轉(zhuǎn)換為Unicode字符串,然后和W版本執(zhí)行相同的代碼。在由A/W版本API引出MBCS程序和Unicode程序前,讓我們先解釋一下Locale和ANSI代碼頁(yè)。

2 Locale和ANSI代碼頁(yè)
    2.1 Locale和LCID
    Locale是指特定于某個(gè)國(guó)家或地區(qū)的一組設(shè)定,包括字符集,數(shù)字、貨幣、時(shí)間和日期的格式等。在Windows中,每個(gè)Locale可以用一個(gè)32位數(shù)字表示,記作LCID。在winnt.h中可以看到LCID的組成。它的高16位表示字符的排序方法,一般為0。在它的低16位中,低10位是primary language的ID,高4位指定sublanguage。sublanguage被用來(lái)區(qū)分同一種語(yǔ)言的不同編碼。下面是部分primary language和sublanguage的常數(shù)定義:

#define LANG_CHINESE 0x04
#define LANG_ENGLISH 0x09
#define LANG_FRENCH 0x0c
#define LANG_GERMAN 0x07

#define SUBLANG_CHINESE_TRADITIONAL 0x01 // Chinese (Taiwan Region)
#define SUBLANG_CHINESE_SIMPLIFIED 0x02 // Chinese (PR China)
#define SUBLANG_ENGLISH_US 0x01 // English (USA)
#define SUBLANG_ENGLISH_UK 0x02 // English (UK)

    好,現(xiàn)在我們可以計(jì)算簡(jiǎn)體中文的LCID了,將sublanguage的常數(shù)左移10位,即乘上1024,再加上primary language的常數(shù):2*1024+4=2052,16進(jìn)制是0804。美國(guó)英語(yǔ)是:1*1024+9=1033,16進(jìn)制是0409。。繁體中文是1*1024+4=1028,16進(jìn)制是0404。

    2.2 代碼頁(yè)
    每個(gè)Locale都聯(lián)系著很多信息,可以通過(guò)GetLocalInfo函數(shù)讀取。其中最重要的信息就是字符集了,即Locale對(duì)應(yīng)的語(yǔ)言文字的編碼。Windows將字符集稱作代碼頁(yè)。

    每個(gè)Locale可以對(duì)應(yīng)一個(gè)ANSI代碼頁(yè)和一個(gè)OEM代碼頁(yè)。Win32 API使用ANSI代碼頁(yè),底層設(shè)備使用OEM代碼頁(yè),兩者可以相互映射。

    例如English (US)的ANSI和OEM代碼頁(yè)分別為“1252 (ANSI - Latin I)”和“437 (OEM - United States)”。 Chinese (PRC)的ANSI和OEM代碼頁(yè)都是“950 (ANSI/OEM - Traditional Chinese Big5)”。 Chinese (TW)的ANSI和OEM代碼頁(yè)都是“936 (ANSI/OEM - Simplified Chinese GBK)”。

    附錄1中有一張很長(zhǎng)的表。列出了我正在使用的Windows所支持的135個(gè)Locale的部分信息,包括 LCID、國(guó)家/地區(qū)名稱、語(yǔ)言名稱、語(yǔ)言縮寫和對(duì)應(yīng)的ANSI代碼頁(yè)。

    2.3 系統(tǒng)Locale、用戶Locale,再談ANSI代碼頁(yè)
    在Windows中,通過(guò)控制面板可以為系統(tǒng)和用戶分別設(shè)置Locale。系統(tǒng)Locale決定代碼頁(yè),用戶Locale決定數(shù)字、貨幣、時(shí)間和日期的格式。這不是一個(gè)好的設(shè)計(jì),后面會(huì)談到它帶來(lái)的問(wèn)題。

    使用GetSystemDefaultLCID函數(shù)和GetUserDefaultLCID函數(shù)分別得到系統(tǒng)和用戶的LCID。有很多材料將這兩個(gè)函數(shù)和另外兩個(gè)函數(shù)混淆:GetSystemDefaultUILanguage和GetUserDefaultUILanguage。

    GetSystemDefaultUILanguage和GetUserDefaultUILanguage得到的是您當(dāng)前使用的Windows版本所帶的UI資源的語(yǔ)言。

    用戶程序缺省使用的代碼頁(yè)是當(dāng)前系統(tǒng)Locale的ANSI代碼頁(yè),可以稱作ANSI編碼,也就是A版本的Win32 API默認(rèn)的字符編碼。對(duì)于一個(gè)未指定編碼方式的文本文件,Windows會(huì)按照ANSI編碼解釋。

    2.4 AppLocale
    如果一個(gè)文本文件采用BIG5編碼,系統(tǒng)當(dāng)前的ANSI代碼頁(yè)是GBK。打開這個(gè)文件,就會(huì)顯示亂碼。例如“中文”在BIG5中的編碼是A4A4、A4E5,這兩個(gè)編碼在GBK中對(duì)應(yīng)的字符是“いゅ”。這是日文的兩個(gè)平假名。

    在Windows XP平臺(tái)有一個(gè)AppLocale程序,可以以指定的語(yǔ)言運(yùn)行非Unicode程序。用Win32dsm打開看一看,其實(shí)它只是在運(yùn)行程序前設(shè)置了兩個(gè)環(huán)境變量。我們可以用個(gè)批處理文件模仿一下:

@ECHO OFF
SET __COMPAT_LAYER=#ApplicationLocale
SET ApplocaleID=0404
start notepad.exe

    在簡(jiǎn)體中文平臺(tái),用這個(gè)批處理文件啟動(dòng)的記事本可以正確顯示BIG5編碼的文本文件。用它打開GBK編碼的文本文件會(huì)怎么樣?“中文”會(huì)被顯示為“笢恅”。設(shè)置這兩個(gè)環(huán)境變量會(huì)作用于當(dāng)前進(jìn)程和其子進(jìn)程。Windows 2000平臺(tái)不支持這個(gè)方法。

 

 

 

3 MBCS程序和Unicode程序
    3.1 與字符編碼有關(guān)的編譯參數(shù)

    讓我們回到Win32 API。我們?cè)诔绦蛑惺褂玫腤in32 API沒有A/W后綴,Windows的頭文件會(huì)根據(jù)編譯參數(shù)UNICODE將沒有后綴的函數(shù)名替換為A版本或W版本,例如:

 

#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif

    C RunTime庫(kù)(CRT)使用_UNICODE和_MBCS來(lái)區(qū)分三套字符串處理函數(shù),分別用于SBCS、MBCS和Unicdoe字符串。SBCS和MBCS分別指單字節(jié)字符串和多字節(jié)字符串。例如_tcsclen的3個(gè)版本分別為strlen、_mbslen和wcslen ,猜猜以下函數(shù)返回幾?

strlen("VOIP網(wǎng)關(guān)");
_mbslen((unsigned char *)"VOIP網(wǎng)關(guān)");
wcslen(L"VOIP網(wǎng)關(guān)");

    答案是8、6、6。L"ANSI字符串"通知編譯器將ANSI字符串轉(zhuǎn)換為Unicode字符串,這是VC++編譯器提供的一個(gè)小甜點(diǎn)。不過(guò)我們應(yīng)該用宏:_T("ANSI字符串")。_T宏只在我們定義了_UNICODE時(shí)才轉(zhuǎn)換。這樣同一套代碼既可以編譯MBCS版本,也可以編譯Unicode版本。

MFC用_UNICODE參數(shù)區(qū)分Unicode版本特有的代碼,決定使用什么版本的導(dǎo)入庫(kù)或靜態(tài)庫(kù)。

    3.2 Unicode程序、MBCS程序和多語(yǔ)言支持
    Unicode程序直接使用Unicode版本的CRT和Win32 API。Unicode程序的運(yùn)行與當(dāng)前的ANSI代碼頁(yè)沒有關(guān)系。MBCS程序的運(yùn)行依賴于ANSI代碼頁(yè)。如果設(shè)計(jì)者和使用者使用不同的代碼頁(yè),就可能出現(xiàn)亂碼。微軟開發(fā)的程序大都是Unicode程序,不管我們?cè)鯓幼儞Q系統(tǒng)Locale,它們總能正常運(yùn)行。

    使用VCL類庫(kù)的Delphi程序都是MBCS程序。VCL框架在程序啟動(dòng)會(huì)調(diào)用GetThreadLocale獲取當(dāng)前用戶的LCID,然后在當(dāng)前目錄查找對(duì)應(yīng)的資源文件,命名規(guī)則是:程序名+'.'+語(yǔ)言縮寫,語(yǔ)言縮寫可以參見附錄1。在找不到時(shí)才會(huì)使用EXE文件中的資源。不過(guò)如果系統(tǒng)LCID是English(United States),用戶LCID是Chinese(PRC),由VCL產(chǎn)生的程序就會(huì)出現(xiàn)亂碼。讀者可以自己分析原因。

    為VCL程序做多語(yǔ)言版本。只要用Delphi自帶的Resource DLL Wizard再做一個(gè)特定語(yǔ)言的資源DLL,原來(lái)的程序都不用改。不過(guò)很多程序員用其它組件做多語(yǔ)言版本,例如TsiLang 。

    MBCS程序雖然也可以做成多語(yǔ)言版本,但它無(wú)法在同時(shí)顯示不同代碼頁(yè)特有的字符,這時(shí)就必須使用Unicode程序了。

    VS.NET文檔中有個(gè)多語(yǔ)言資源的例子:SatDLL。它只用Win32 API的例子,卻用了VC7項(xiàng)目。我在學(xué)習(xí)時(shí)將它改成了VC6項(xiàng)目,并糾正了它的兩個(gè)問(wèn)題:
1、用GetUserDefaultUILanguage讀到的是Windows資源版本,不是當(dāng)前用戶設(shè)置的代碼頁(yè)。
2、啟動(dòng)時(shí)沒有使用資源DLL里的菜單。

    在我的個(gè)人主頁(yè)(http://fmddlmyy.home4u.china.com)上可以下載修改過(guò)的SatDLL。這個(gè)程序說(shuō)明了支持多語(yǔ)言資源的基本思路:將不同語(yǔ)言資源放到不同的DLL中,在程序啟動(dòng)時(shí)根據(jù)當(dāng)前Locale裝載對(duì)應(yīng)的資源DLL。必要時(shí)動(dòng)態(tài)切換資源。為了標(biāo)記不同語(yǔ)言的資源,可以將它們放到不同的目錄中,以LCID作為目錄名,例如“2052”、“1033”。當(dāng)然我們也可以用其它方法聯(lián)系LCID和資源DLL。

    MFC程序可以在App類的InitInstance函數(shù)中用AfxSetResourceHandle函數(shù)設(shè)置資源DLL。在Delphi中動(dòng)態(tài)切換資源可以參考Delphi Demo目錄RichEdit項(xiàng)目的ReInit.pas。在讀取當(dāng)前設(shè)定時(shí),建議用GetSystemDefaultLCID函數(shù),因?yàn)橄到y(tǒng)Locale決定ANSI代碼頁(yè)。

    3.4 資源和亂碼
    通過(guò)檢查可執(zhí)行文件,我們可以確定VC和Delphi的資源編譯器都以Unicode保存字符資源。在VC環(huán)境編輯資源時(shí),我們會(huì)指定資源的代碼頁(yè)。編譯器根據(jù)資源的代碼頁(yè),將其轉(zhuǎn)換到Unicode。

    Unicode程序直接使用以Unicode編碼保存的資源。MBCS程序需要將Unicode資源先轉(zhuǎn)換回當(dāng)前ANSI代碼頁(yè),然后再使用。如果資源中的Unicode字符串不能映射到當(dāng)前代碼頁(yè)中的字符,就會(huì)出現(xiàn)??。

    例如Windows的標(biāo)準(zhǔn)對(duì)話框也會(huì)出現(xiàn)亂碼。假設(shè)我們使用簡(jiǎn)體中文Windows,當(dāng)前Locale是Chinese (TW),我們的程序是MBCS的,使用標(biāo)準(zhǔn)的打開文件對(duì)話框。因?yàn)樵贐IG5中沒有“開”這個(gè)字,所以“打開”會(huì)被顯示成“打?”。將程序編譯成Unicode版本,就可以避免這個(gè)問(wèn)題。

    如果字符不是保存在資源中,而是硬編碼在程序中。然后開發(fā)者和用戶使用不同的代碼頁(yè),就會(huì)導(dǎo)致亂碼。假設(shè)開發(fā)者的Locale是Chinese (PRC),用戶的Locale是English (US),程序中硬編碼了字符串“文件”。 Chinese (PRC)的ANSI代碼頁(yè)是GBK,“文件”的編碼“CE C4 BC FE”。English (US)的ANSI代碼頁(yè)是Latin I,用戶按照Latin I編碼去解釋“CE C4 BC FE”,就會(huì)看到“???t”。

    回答我前面提過(guò)的一個(gè)問(wèn)題:Delphi程序根據(jù)用戶LCID轉(zhuǎn)換資源中的字符串。如果用戶LCID是Chinese (PRC),系統(tǒng)LCID是English (US)。那么資源中的Unicode字符串會(huì)被轉(zhuǎn)換為GBK編碼,然后按照Latin I顯示,這時(shí)我們看到的就是類似“???t”的東東,不是??。

    既然資源是以Unicode保存的,MBCS程序如果不將其轉(zhuǎn)換到ANSI代碼頁(yè),而用W版本的函數(shù)直接顯示,就不會(huì)產(chǎn)生亂碼。例如MFC程序菜單里的中文,在English (US)的Locale也可以正常顯示。不過(guò)這取決于各部分代碼的具體實(shí)現(xiàn),menu bar控件里的中文在English (US)的Locale會(huì)全部顯示成??。

進(jìn)一步的參考資料


    本文的第0節(jié)和附錄0主要參考了《Inside Windows 2000 Third Edition》,國(guó)內(nèi)出過(guò)該書的影印版。DDK文檔中有大量Windows內(nèi)核的信息。用Win32dsm和各種調(diào)試器查看Windows系統(tǒng)文件可以獲得更直接的信息。

    關(guān)于Window程序的字符編碼,最好的參考資料是winnt.h等SDK的包含文件、VCL、MFC、CRT的源文件。我們不需要閱讀它們,只要找到自己感興趣的信息就可以了,用Source Insight可能方便一些。

    本文所談的不是什么萬(wàn)古不遷的道理,只是別的程序員的一些設(shè)定,我們因?yàn)樾枰褂盟麄兊某绦颍杂斜匾私庖恍┘?xì)節(jié)。研究問(wèn)題的方法和興趣永遠(yuǎn)比問(wèn)題本身重要,如一句拉丁俗語(yǔ)所說(shuō):res, non verba,實(shí)質(zhì)勝于文字。

posted on 2008-06-30 12:27 大龍 閱讀(431) 評(píng)論(0)  編輯 收藏 引用


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲欧洲日本mm| 亚洲国产你懂的| 欧美在线亚洲一区| 免费在线观看精品| 亚洲精品美女久久7777777| 欧美电影免费观看高清完整版| 亚洲黄色一区二区三区| 亚洲视频免费观看| 国产情侣一区| 蜜臀久久99精品久久久画质超高清 | 欧美日韩免费在线| 亚洲女人天堂av| 美女网站久久| 亚洲午夜精品一区二区三区他趣| 国产精品成人免费| 久久久久五月天| 日韩一级黄色片| 久久尤物视频| 亚洲一区二区在线免费观看视频| 国产三区精品| 欧美激情国产日韩精品一区18| 在线亚洲精品| 欧美激情第1页| 校园春色综合网| 亚洲福利小视频| 国产精自产拍久久久久久| 免费成人毛片| 欧美在线视频a| 99re8这里有精品热视频免费| 久久亚洲精品欧美| 亚洲在线中文字幕| 亚洲日本久久| 国内精品久久久久影院色| 欧美三级电影一区| 久久综合一区二区| 午夜精品免费视频| 99国产精品私拍| 亚洲国产精品高清久久久| 久久国产一区| 亚洲欧美日韩国产中文在线| 91久久精品一区二区三区| 国产日韩精品电影| 欧美性感一类影片在线播放 | 欧美刺激午夜性久久久久久久| 亚洲亚洲精品三区日韩精品在线视频 | 日韩视频永久免费观看| 国内精品福利| 国产精品永久免费在线| 欧美日韩中文另类| 欧美精品久久99| 免费看av成人| 久久一区二区视频| 久久精品2019中文字幕| 午夜影视日本亚洲欧洲精品| 中国成人亚色综合网站| 亚洲麻豆av| 日韩视频永久免费| 亚洲日本中文字幕免费在线不卡| 欧美激情国产日韩| 欧美国产精品| 亚洲成人中文| 亚洲精华国产欧美| 亚洲国产精品热久久| 欧美v亚洲v综合ⅴ国产v| 久久躁狠狠躁夜夜爽| 久久久久久亚洲精品中文字幕| 欧美在线一二三区| 久久国产日韩| 久久夜色精品| 久久综合久久综合这里只有精品| 久久精品视频免费播放| 久久久精品动漫| 久久人人爽国产| 蜜桃久久精品乱码一区二区| 麻豆精品一区二区综合av| 美女网站在线免费欧美精品| 欧美成人精品在线观看| 欧美国产在线观看| 亚洲欧洲在线看| 一本久久a久久精品亚洲| 亚洲少妇一区| 欧美亚洲免费电影| 久久一区二区三区国产精品| 免费成人av在线| 欧美精品一区在线播放| 欧美午夜电影一区| 国产欧美va欧美不卡在线| 国产自产v一区二区三区c| 在线观看av一区| 亚洲免费观看高清完整版在线观看| 99视频精品在线| 午夜一区二区三区不卡视频| 久久黄色网页| 欧美激情影音先锋| 99xxxx成人网| 欧美专区亚洲专区| 欧美成人午夜激情在线| 国产精品久久久久久久久久免费| 国产老肥熟一区二区三区| 尤妮丝一区二区裸体视频| 亚洲美女av黄| 久久xxxx| 亚洲人成网站在线观看播放| 亚洲综合精品一区二区| 狂野欧美激情性xxxx欧美| 欧美日韩国产在线看| 国产精品一区二区三区久久久 | 欧美亚洲第一页| 极品尤物一区二区三区| 一区二区高清| 久久伊人精品天天| 亚洲精品一区二区三区在线观看 | 欧美少妇一区二区| 黄色av成人| 亚洲先锋成人| 欧美成人免费大片| 亚洲一区综合| 欧美精品xxxxbbbb| 好看的日韩视频| 亚洲已满18点击进入久久| 美女亚洲精品| 亚洲欧美在线一区二区| 欧美精品一区二区三区蜜臀| 国产一区美女| 亚洲欧美日本伦理| 亚洲国产精品久久久久| 性色av一区二区三区在线观看| 欧美另类在线播放| 在线观看亚洲视频| 欧美一区亚洲| 在线综合+亚洲+欧美中文字幕| 久久视频免费观看| 国产日韩亚洲欧美综合| 中文在线资源观看视频网站免费不卡| 鲁大师影院一区二区三区| 亚洲一区在线观看免费观看电影高清| 欧美国产亚洲精品久久久8v| 伊人久久大香线| 久久激情视频久久| 亚洲综合999| 欧美系列精品| 亚洲婷婷国产精品电影人久久 | 99精品欧美一区二区三区| 美女在线一区二区| 在线播放日韩| 久久久久久穴| 欧美在线影院| 国产午夜久久久久| 久久精品三级| 小黄鸭视频精品导航| 国产精品一区视频网站| 亚洲影院色无极综合| 亚洲麻豆av| 欧美日韩在线精品| 亚洲图色在线| 99精品视频免费观看视频| 欧美日本在线看| 一本色道久久综合亚洲精品不卡| 最新日韩av| 欧美剧在线观看| 一区二区三区 在线观看视频| 亚洲激精日韩激精欧美精品| 欧美成人自拍| 亚洲色无码播放| 亚洲午夜国产成人av电影男同| 欧美三级午夜理伦三级中视频| 亚洲视频在线观看网站| 中文欧美日韩| 国产欧美日韩亚洲一区二区三区| 欧美中文字幕在线观看| 欧美亚洲自偷自偷| 在线看日韩欧美| 亚洲国产精品女人久久久| 欧美久久精品午夜青青大伊人| 在线一区二区三区四区| 中文有码久久| 国产欧美日韩综合| 久久综合给合| 欧美成人午夜免费视在线看片 | 午夜精品久久| 一区二区三区在线观看欧美 | 久久爱www.| 亚洲黄色免费| 99re66热这里只有精品3直播| 国产精品国产一区二区| 久久久久久久91| 免费试看一区| 亚洲在线视频网站| 久久国产一区| 亚洲免费高清视频| 亚洲午夜黄色| 在线观看亚洲精品| 日韩午夜激情av| 韩日精品视频一区| 91久久久亚洲精品| 国产日韩欧美在线看| 欧美激情亚洲综合一区| 国产精品美女www爽爽爽视频| 久久综合伊人77777麻豆| 欧美日韩精品高清|