c語言中的記憶體模式,near far huge關鍵字

來源:互聯網
上載者:User

標籤:自己的   全域變數   建立   初始   錯誤   精確   限制   定址方式   .net   

本文章是轉載來自6044576

編譯模式是指如何在記憶體中放置程式碼及資料,如何分配堆棧,並確認佔用的記憶體大小及如何存取它們,當指定記憶體模式(編譯模式)以後,語言編譯器將按事先選擇好的記憶體模式編譯組織程式,C 語言中提供了6種編譯模式,這6種模式是:微模式(Tiny),小模式(Small),中模式(Medium),緊湊模式(Compact),大模式(Large)和巨模式(Huge)。使用者可以按照自己的程式大小及需要進行選擇。

  所謂小程式就是指程式只有一個程式段,大小不超過64KB,預設的碼(函數)指標是near(近程指標)。所謂大程式就是指程式有多個程式段,每個程式段不超過64KB,但總程式量可超過64KB,預設的碼指標是far(遠程指標)。小資料就是指資料只有一個資料區段,預設的資料指標是near。大資料就是指資料有多個資料區段,預設的資料指標是far。

C語言編譯模式—微模式(Tiny)
在微模式下程式中的資料及代碼均放在同一段內,即它們不超過 64KB。在微模式下程式碼片段、堆棧段和資料區段的段地址均相同,即CS=DS=SS=ES。在這個段內,碼首先裝入,地址最低,接著是靜態變數和全域變數。然後是堆,最後是堆棧。堆棧和堆都是動態,堆從低地址往高地址增長,堆棧從高地址往低地址增長,若兩者相等,則表示空間耗完了。在微模式下,資料指標都是 near,一般小程式可採用此編譯模式進行編譯。還可用 DOS 中的 EXE2BIN 轉換程式將.EXE 程式轉換成.COM 程式。

  程式碼片段、資料區段和堆棧段均在同一段內,對它們進行定址時,均以同一地址位移的參考點,具有這種特點的段又稱為屬於同一組段(DGROUP),棧是向上生長的,即每壓棧一次,棧指標SP減2,即向地址減少的方向移動,它開始的初始值指向棧底,即0xffff(64KB)。堆是向下生長的,即向增加地址的方向改變。由圖中可以看出堆和棧地址相向生長,當兩者未相遇時,便出現了自由空間。一般程式均是這種狀態,當佔用棧地址較多時,兩者可能重合并覆蓋部分堆空間。

C語言編譯模式—小模式(Small)
在小模式下,程式中的代碼放在64KB的程式碼片段內,資料放在64KB的資料區段內。在小模式下,棧段、附加資料區段和資料區段均指向同一地址,它們合三為一,即DS=SS=ES,指標都是near,一般程式均採用小模式編譯。資料區段、堆棧段和附加段為同一段組,即它們的位移地址均以同一段地址為參考點。除了和資料/堆棧共用一個段的堆外,還有一個遠堆。

C語言編譯模式—中模式(Medium)
在中模式下,所有資料放在64KB的資料區段內,因而資料區段內使用near,代碼量可以大於64KB(允許達到1MB),因而可以在不同的程式碼片段內,程式碼片段使用(far遠程指標)。來自不同源檔案的碼模組放在不同的碼段內。嚴格的講,同一個源檔案內的各函數也是放在不同的碼段的。這種編譯模式適用於大代碼量、小資料量的大程式。還有一個遠堆。

C語言編譯模式—緊湊模式(Compact)
在緊湊模式下,資料量超過64KB時,可放在多個資料區段中,資料區段內的指標是(far)。代碼量不超過64KB,在一個段內,因而程式碼片段內指標為近程的(near)。但在該模式下,待用資料仍不能超過64KB,堆用far指標來存取。代碼、待用資料、堆棧、堆各有自己的段。堆只有遠堆,沒有近堆。

C語言編譯模式—大模式(Large)
大模式下,代碼及資料均採用far指標,且都可達到1MB。待用資料、堆棧、堆同緊湊模式,代碼同中模式。待用資料仍跟緊湊模式一樣,不能超過64KB。

C語言編譯模式—巨模式(Huge)
巨模式下,程式碼片段及資料區段均用far指標,代碼分布在不同的程式碼片段內,資料也分布在不同的資料區段內,它們來自不同的來源程式,大堆棧只有一個。而且待用資料大小允許超過64KB。

緊湊模式、大模式、巨模式資料區大小均允許超過64KB,即可以用資料far指標對不同資料區段內的資料進行存取,它們同稱為大資料存放區模式。但有一點不同:緊湊模式和大模式按 C 的規定,其待用資料,即如數組、結構或其他類型的資料被定義為靜態類型時,其資料量不能超過64KB,而只有巨模式才允許超過64KB。在大資料存放區模式下,堆和棧分別在不同段內,多以動態資料和局部變數的形式存放,這樣就不受64KB大小的限制,棧的增長不會影響堆的空間。

  無論採用哪一種編譯模式,C來源程式編譯產生的程式碼和資料量都不能超過64KB,對於超過的來源程式,可以視代碼或資料多少將其分解成兩個或多個程式分別編譯。大代碼配量序要選用大代碼編譯模式(中模式、大模式和巨模式),大資料配量序應選用大資料編譯模式(緊湊模式、大模式和巨模式),這樣編譯產生的.obj 檔案將會帶給串連程式資訊,將代碼和資料安排在不同段內。這樣產生的.exe 檔在載入時將告訴 DOS 該程式應如何裝入程式碼片段和資料區段,如何初始化寄存器。這樣,就可確定在不同編譯模式下開闢資料區的大小,即大於64KB,或不超過64KB。

在TC中記憶體模式與far、near、huge等關鍵字又有著密切的關係。在tiny、small模式下,所有的函數定義、全域變數定義和指標變數的定義,如果沒有顯示的加上far、near、huge等關鍵字,都預設為使用了near關鍵字;在medium模式下,函數定義預設使用了far關鍵字,變數定義預設使用了near關鍵字;在compact模式下函數定義模式使用了near關鍵字,變數定義預設使用了far關鍵字;large模式下函數定義和變數定義模認使用了far關鍵字;huge模式下函數定義模認使用了far關鍵字,變數定義預設使用了huge關鍵字。

    near、far、huge關鍵字的真正含義是什嗎?這三個關鍵字只能用於修改函數、全域變數和指標變數,對於非指標類型的局部變數,這些關鍵字沒有實際意義。這些關鍵字用於修飾函數時,huge的含義與far相同,用於指明該函數的調用方式為far調用方式,即調用時需要一個段值和一個段位移組成的32bits調用地址,使用far call進行跳轉,跳轉前先壓棧儲存當前CS:IP。near修飾函數時,用於指明該函數的調用方式為near調用方式,調用時只需要一個16bits的近地址,即當前CS的段內位移。

      當這三個關鍵字用於修飾指標時,near型指標實質上為16bits的無符號整型數,該整數給出了所指向變數在當前資料區段內的位移地址,也就是說,在使用near型指標定址時實際上是進行如下的定址操作:[DS:指標變數值]。對於far型的指標變數,可以定址1MB地址空間的任意一個地方,far型指標的實質是一個32bits的整型數,高16bits為段值,低16bits為段內位移,Turbo C中在使用far型指標時,會先將高16bits放入ES寄存器中,然後再進行如下的定址操作:[ES:指標變數低16bits值]。對於hug型的指標變數,與far性指標變數的不同之處在於,在對far型指標變數進行+/++/-/--等操作時,far型指標變數保持段值不變(也就是高16bits),而只對段內位移進行加減操作,所以會出現段內迴繞的現象,而huge型的指標,在進行加減操作時將會自動的改變段值,不會出現段內迴繞。所以給人的感覺就是huge指標能比far指標定址更大的記憶體空間。

      對於局部變數,由於是建立在堆棧上,所以near、far等關鍵字將不具備任何意義,因為建立在堆棧上的變數的定址方式就只有一種,即使用sp和bp維護函數堆棧,利用bp+/-一個位移來定址函數參數變數和局部變數。這樣的定址方式是固定而唯一的,near和far等關鍵字都派不上用場,這裡的near和far將沒有任何的實際含義。

    對於使用near、far和huge修飾的全域變數的含義也很容易理解了。near型的全域變數,被分配到了當前的資料區段上,定址這個變數只需要一個16bits的位移量,而far型全域變數在定址時,需要給出段值和位移量。huge型數組可以使用大於64K的記憶體空間。

    far、near、huge型指標變數之間的相互轉換,從小尺寸的指標到大尺寸的指標將進行自動的類型轉換,轉換方式為加上當前的DS形成32bits的指標。從大尺寸的指標到小尺寸的指標需要進行強制類型轉換,轉換的結果為只保留低16bits,但是這樣俄轉換沒有實際的意義或者說用處不大,並且極其容易引入記憶體訪問的錯誤,所以要嚴格避免使用。

 需要注意的是,near、far、huge三個關鍵字的使用,還需要記憶體模式的緊密配合。但並不是說tiny模式下就不能使用near、far、huge三個關鍵字。tiny模式下同樣可以定義如下的指標:
    char far *pbuf = 0xA0000000;
    並且我能保證這個指標能夠絕對正確的工作,對函數、全域變數的修飾也是如此。但是如何正確的工作,如何才是最和合理的方式,請自己思考了。基本的原理我也講的很清楚,就不再多費唇舌。

    Turbo C中,我想最為困惑的就是記憶體模式了,我也是費了很多時間和精力,通過分析Turbo C的彙編代碼的出的以上結論。許多朋友都對此很困惑,所以這部分重點講了下,和大家分享。如有不正確之處,請不吝賜教,旨在拋磚引玉。tcc編譯彙編代碼的方法為:tcc -c -mt -S filename.c,-c指明compile only,-mx用於指定記憶體模式,-S指明產生彙編代碼,如果大家有興趣可以嘗試使用這個方法分析tcc編譯結果的彙編代碼,從而更加深刻的理解C與彙編的關係。

    當我們在編寫、製作並向使用者提供自己的庫檔案時,也需要注意記憶體模式的匹配,否則在進行連結時會存在問題。一個較為簡單的方法就是向使用者提供全套記憶體模式的庫檔案,這也是Turbo C的ANSI C庫的做法,前文已經提到。如果不想提供多個記憶體模式的庫檔案,可以對程式中每個函數、全域變數和指標變數進行顯式的型別宣告,以精確定義每個變數的類型。

c語言中的記憶體模式,near far huge關鍵字

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.