久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      深入認(rèn)識(shí)Turbo C編譯器

      原帖及討論:http://bbs.bccn.net/thread-117971-1-1.html

          有誰真正的理解過一個(gè)編譯器呢?許多人認(rèn)為TC很簡單很落后,但是即便是這樣簡單的工具,到底有幾個(gè)人真正的深入理解了呢?一個(gè)簡單的編譯器都不能理解,如何能成為高手,如何能深入的使用更加高級(jí)的工具呢?不要以為自己使用的是VC就很了不起,因?yàn)槭褂眠@樣傻瓜化的工具只能讓你看不到事物的本質(zhì)。接下來我們就來深入的認(rèn)識(shí)Turbo C編譯器。

          廣義的編譯器,包括了代碼編譯器(compiler),目標(biāo)文件鏈接器(linker),庫文件管理工具(如tc的tlib,gcc的ar),編譯驅(qū)動(dòng)工具(如VC的NMake,gcc的make),ANSI c/c++標(biāo)準(zhǔn)的頭文件和庫文件,擴(kuò)展的頭文件和庫文件,集成開發(fā)環(huán)境(IDE),等等與編譯相關(guān)的工具,所有這些工具的集合,就組成了廣義上的編譯器。

          狹義的編譯器,則僅指compiler。compiler只負(fù)責(zé)將源代碼,即.c/.cxx/.cpp文件編譯成為目標(biāo)文件.o/.obj。編譯過程的輸入是源文件,包括自己書寫的.c和.h以及系統(tǒng)提供的.h文件,編譯的輸出是目標(biāo)文件。需要強(qiáng)調(diào)的一點(diǎn)時(shí),在compile階段,只處理源文件,所以不需要庫文件和額外的目標(biāo)文件的參與,因此,只要代碼在語法上沒有錯(cuò)誤,compile就一定能產(chǎn)生目標(biāo)文件。

          對(duì)于一個(gè)廣義的編譯器來說以下幾個(gè)部分是必備的:1.compiler,2.linker,3.系統(tǒng)提供的頭文件和庫文件。前面已經(jīng)介紹了compiler,接下來看linker。

          linker的功能是將目標(biāo)文件進(jìn)行裝配,將浮動(dòng)的地址變?yōu)榇_定的地址,這個(gè)工作是通過修改目標(biāo)文件的重定位項(xiàng)來實(shí)現(xiàn)的,其具體的過程可以參考”Linker & loader”這本書,這是一本詳細(xì)介紹linker和loader的好書,在此做個(gè)推薦??傊?,link這一階段處理的輸入是目標(biāo)文件,其輸出是可執(zhí)行文件,或動(dòng)態(tài)庫。

          任何一個(gè)編譯器都會(huì)提供庫文件和與之對(duì)應(yīng)的頭文件,C/C++編譯器一般都提供ANSI C/C++的庫和相應(yīng)的頭文件。

          從現(xiàn)在起我們就需要建立起一個(gè)概念,就是廣義的編譯過程,實(shí)際上是由編譯和鏈接兩個(gè)基本步驟組成的,如果能深刻的理解這兩個(gè)步驟,就是一大進(jìn)步了。

          在編譯器里,有一些默認(rèn)的規(guī)定,我們需要了解。在編譯器中,bin目錄用于存放compiler、linker等工具,include目錄用于存放頭文件,lib目錄用存放庫文件,大多數(shù)的編譯器的目錄就是按這個(gè)來組織的。

      接下來看Turbo C為我們提供了些什么(請(qǐng)到我的網(wǎng)站下載我動(dòng)手制作的改良版TC編譯器)。
      bin目錄中:
          CPP.EXE    是一個(gè)C語言預(yù)處理工具,就是負(fù)責(zé)對(duì)源代碼進(jìn)行預(yù)編譯處理,不要理解為c++編譯器
          TCC.EXE    是一個(gè)C語言的編譯器,可以將代碼編譯為目標(biāo)文件,并且能自動(dòng)調(diào)用tlink鏈接生成可執(zhí)行文件
          TASM.exe   是一個(gè)匯編工具,可以將x86的匯編代碼編譯成為目標(biāo)文件
          TLink.exe  是一個(gè)鏈接器,負(fù)責(zé)對(duì)目標(biāo)文件、庫文件等進(jìn)行鏈接
          TLib.exe   是一個(gè)庫文件管理工具,可以將多個(gè)目標(biāo)文件打包到一個(gè)庫文件里
          BGIOBJ.exe 可以將BGI文件轉(zhuǎn)換為.obj文件
          make.exe   符合GNU標(biāo)準(zhǔn)的make工具,可用于代碼編譯的管理(只有在我制作的TC中提供)
          TURBOC.CFG tcc默認(rèn)的編譯參數(shù)配置文件
      以上所有的工具的使用方法都可以直接鍵入相應(yīng)的命令進(jìn)行查看,如鍵入tcc即可看到tcc的使用方法,因此這里不再講解。

      BGI目錄中:
          EGAVGA.BGI 是EGAVGA的bgi驅(qū)動(dòng)

      FONT目錄中:存放了BGI所使用到的各種字體文件

      INCLUDE目錄中:是Turbo C的庫函數(shù)的所有的頭文件,當(dāng)要使用某個(gè)庫函數(shù)時(shí)可以在這個(gè)目錄下搜索,找到其所在文件和原型,這里不在詳細(xì)敘述。

      重點(diǎn)講一下Lib目錄:
          init.obj文件是C語言的啟動(dòng)代碼,它負(fù)責(zé)建立C程序運(yùn)行的堆棧、初始化內(nèi)存、調(diào)用C入口函數(shù)等。這部分代碼是使用匯編書寫的,其源代碼可以在TC(官方版)里找到,名稱為Init.ASM。
          c0t.obj、c0s.obj、c0m.obj、c0c.obj、c0l.obj和c0h.obj文件,都是c code的入口函數(shù)實(shí)現(xiàn),入口函數(shù)將會(huì)讀取環(huán)境變量,并調(diào)用c語言中的main函數(shù),將命令行參數(shù)傳入main函數(shù)中,之后的控制權(quán)就交給了main函數(shù),也就是我們常說的C的主函數(shù)main。由于Turbo C中有不同的內(nèi)存模式,因此以上6個(gè)文件分別對(duì)應(yīng)TC中6種不同的內(nèi)存模式。
          cc.lib、ch.lib、cl.lib、cm.lib、cs.lib五個(gè)文件都是TC提供的ANSI C標(biāo)準(zhǔn)庫的庫文件,分別對(duì)用不同的內(nèi)存模式:
          cc compact模式
          ch huge模式
          cl large模式
          cm medium模式
          cs small模式

      由于不同模式參數(shù)的入棧方式、函數(shù)的調(diào)用方式等等都各不一樣,所以代碼也不一樣,因此需要分別提供各個(gè)模式的庫文件。

          再講一下Turbo C中的內(nèi)存模式。內(nèi)存模式的出現(xiàn)不是由編譯器決定的,而是由處理器的尋址方式?jīng)Q定的,在8086處理器中為了在16位寄存器的基礎(chǔ)上尋址20位的地址,引入了段寄存器和分段尋址的方式。在編譯器這一級(jí),利用這種段式的尋址方式,可以實(shí)現(xiàn)多種不同的存儲(chǔ)分配方法,因此就產(chǎn)生了所謂的不同的內(nèi)存模式。
          1. tiny模式:   程序和數(shù)據(jù)在一個(gè)64K字節(jié)的段內(nèi)
          2. small模式:  獨(dú)立的代碼段(64KB)和獨(dú)立的數(shù)據(jù)段(64KB)
          3. medium模式: 單個(gè)數(shù)據(jù)段(64KB)和多個(gè)代碼段(1MB)
          4. compack模式:單個(gè)代碼段(64KB)和多個(gè)數(shù)據(jù)段(1MB)
          5. large模式:  多個(gè)代碼段(1MB)和多個(gè)數(shù)據(jù)段(1MB),數(shù)據(jù)指針不能跨越段邊界,否則將回繞
          6. huge模式:   多個(gè)代碼段(1MB)和多個(gè)數(shù)據(jù)段(1MB),數(shù)據(jù)指針可以跨越段邊界,不會(huì)回繞

          在TC中內(nèi)存模式與far、near、huge等關(guān)鍵字又有著密切的關(guān)系。在tiny、small模式下,所有的函數(shù)定義、全局變量定義和指針變量的定義,如果沒有顯示的加上far、near、huge等關(guān)鍵字,都默認(rèn)為使用了near關(guān)鍵字;在medium模式下,函數(shù)定義默認(rèn)使用了far關(guān)鍵字,變量定義默認(rèn)使用了near關(guān)鍵字;在compact模式下函數(shù)定義模式使用了near關(guān)鍵字,變量定義默認(rèn)使用了far關(guān)鍵字;large模式下函數(shù)定義和變量定義模認(rèn)使用了far關(guān)鍵字;huge模式下函數(shù)定義模認(rèn)使用了far關(guān)鍵字,變量定義默認(rèn)使用了huge關(guān)鍵字。

          near、far、huge關(guān)鍵字的真正含義是什么?這三個(gè)關(guān)鍵字只能用于修改函數(shù)、全局變量和指針變量,對(duì)于非指針類型的局部變量,這些關(guān)鍵字沒有實(shí)際意義。這些關(guān)鍵字用于修飾函數(shù)時(shí),huge的含義與far相同,用于指明該函數(shù)的調(diào)用方式為far調(diào)用方式,即調(diào)用時(shí)需要一個(gè)段值和一個(gè)段偏移組成的32bits調(diào)用地址,使用far call進(jìn)行跳轉(zhuǎn),跳轉(zhuǎn)前先壓棧保存當(dāng)前CS:IP。near修飾函數(shù)時(shí),用于指明該函數(shù)的調(diào)用方式為near調(diào)用方式,調(diào)用時(shí)只需要一個(gè)16bits的近地址,即當(dāng)前CS的段內(nèi)偏移。

          當(dāng)這三個(gè)關(guān)鍵字用于修飾指針時(shí),near型指針實(shí)質(zhì)上為16bits的無符號(hào)整型數(shù),該整數(shù)給出了所指向變量在當(dāng)前數(shù)據(jù)段內(nèi)的偏移地址,也就是說,在使用near型指針尋址時(shí)實(shí)際上是進(jìn)行如下的尋址操作:[DS:指針變量值]。對(duì)于far型的指針變量,可以尋址1MB地址空間的任意一個(gè)地方,far型指針的實(shí)質(zhì)是一個(gè)32bits的整型數(shù),高16bits為段值,低16bits為段內(nèi)偏移,Turbo C中在使用far型指針時(shí),會(huì)先將高16bits放入ES寄存器中,然后再進(jìn)行如下的尋址操作:[ES:指針變量低16bits值]。對(duì)于hug型的指針變量,與far性指針變量的不同之處在于,在對(duì)far型指針變量進(jìn)行+/++/-/–等操作時(shí),far型指針變量保持段值不變(也就是高16bits),而只對(duì)段內(nèi)偏移進(jìn)行加減操作,所以會(huì)出現(xiàn)段內(nèi)回繞的現(xiàn)象,而huge型的指針,在進(jìn)行加減操作時(shí)將會(huì)自動(dòng)的改變段值,不會(huì)出現(xiàn)段內(nèi)回繞。所以給人的感覺就是huge指針能比far指針尋址更大的內(nèi)存空間。

          對(duì)于局部變量,由于是創(chuàng)建在堆棧上,所以near、far等關(guān)鍵字將不具備任何意義,因?yàn)閯?chuàng)建在堆棧上的變量的尋址方式就只有一種,即使用sp和bp維護(hù)函數(shù)堆棧,利用bp+/-一個(gè)偏移來尋址函數(shù)參數(shù)變量和局部變量。這樣的尋址方式是固定而唯一的,near和far等關(guān)鍵字都派不上用場,這里的near和far將沒有任何的實(shí)際含義。

          對(duì)于使用near、far和huge修飾的全局變量的含義也很容易理解了。near型的全局變量,被分配到了當(dāng)前的數(shù)據(jù)段上,尋址這個(gè)變量只需要一個(gè)16bits的偏移量,而far型全局變量在尋址時(shí),需要給出段值和偏移量。huge型數(shù)組可以使用大于64K的內(nèi)存空間。

          far、near、huge型指針變量之間的相互轉(zhuǎn)換,從小尺寸的指針到大尺寸的指針將進(jìn)行自動(dòng)的類型轉(zhuǎn)換,轉(zhuǎn)換方式為加上當(dāng)前的DS形成32bits的指針。從大尺寸的指針到小尺寸的指針需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,轉(zhuǎn)換的結(jié)果為只保留低16bits,但是這樣俄轉(zhuǎn)換沒有實(shí)際的意義或者說用處不大,并且極其容易引入內(nèi)存訪問的錯(cuò)誤,所以要嚴(yán)格避免使用。

          需要注意的是,near、far、huge三個(gè)關(guān)鍵字的使用,還需要內(nèi)存模式的緊密配合。但并不是說tiny模式下就不能使用near、far、huge三個(gè)關(guān)鍵字。tiny模式下同樣可以定義如下的指針:
          char far *pbuf = 0xA0000000;
          并且我能保證這個(gè)指針能夠絕對(duì)正確的工作,對(duì)函數(shù)、全局變量的修飾也是如此。但是如何正確的工作,如何才是最和合理的方式,請(qǐng)自己思考了?;镜脑砦乙仓v的很清楚,就不再多費(fèi)唇舌。

          Turbo C中,我想最為困惑的就是內(nèi)存模式了,我也是費(fèi)了很多時(shí)間和精力,通過分析Turbo C的匯編代碼的出的以上結(jié)論。許多朋友都對(duì)此很困惑,所以這部分重點(diǎn)講了下,和大家分享。如有不正確之處,請(qǐng)不吝賜教,旨在拋磚引玉。tcc編譯匯編代碼的方法為:tcc -c -mt -S filename.c,-c指明compile only,-mx用于指定內(nèi)存模式,-S指明生成匯編代碼,如果大家有興趣可以嘗試使用這個(gè)方法分析tcc編譯結(jié)果的匯編代碼,從而更加深刻的理解C與匯編的關(guān)系。

          當(dāng)我們?cè)诰帉?、制作并向用戶提供自己的庫文件時(shí),也需要注意內(nèi)存模式的匹配,否則在進(jìn)行鏈接時(shí)會(huì)存在問題。一個(gè)較為簡單的方法就是向用戶提供全套內(nèi)存模式的庫文件,這也是Turbo C的ANSI C庫的做法,前文已經(jīng)提到。如果不想提供多個(gè)內(nèi)存模式的庫文件,可以對(duì)程序中每個(gè)函數(shù)、全局變量和指針變量進(jìn)行顯式的類型聲明,以精確定義每個(gè)變量的類型。

          關(guān)于TC中各種編譯工具的使用方法,可以直接參考其幫助,并且許多參考文檔都有說明,這里我就不再詳細(xì)介紹了。關(guān)于GNU的make工具的使用,同樣也可以在網(wǎng)上找到參考資料,因此不再介紹。還有就是關(guān)于Turboc的BGI驅(qū)動(dòng)的,我也研究過多時(shí),我這里有詳細(xì)的參考文檔,并且已經(jīng)實(shí)現(xiàn)了一個(gè)BGI的框架,對(duì)于有興趣自己開發(fā)BGI的朋友,我們可以交流。當(dāng)然Turbo C最大的魅力,也是最讓我著迷的也就是它簡單而直接的圖形編程,可以直接的訪問硬件資源,因此能收獲許多底層、硬件相關(guān)的知識(shí)。當(dāng)然Turbo C的圖形編程是一個(gè)很大的課題,我也在不斷的學(xué)習(xí)和研究之中,如果有機(jī)會(huì)也會(huì)繼續(xù)寫作相關(guān)的文章。

          關(guān)于TC,還有許多值得介紹的,但是一時(shí)也想不起來了,本來打算寫的更加細(xì)致一點(diǎn),但是心中只有這么點(diǎn)墨水,現(xiàn)在墨水已經(jīng)寫干了,等以后有時(shí)間,有墨水以后再繼續(xù)這個(gè)話題吧。OK,結(jié)束了。

                     RockCarry工作室 陳凱
                     22:31 2007-1-24

      自制的 Turbo C 2.0 編譯器下載地址:
      http://home.goofar.com/npucs/

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)