在c語言中,指標變數的值就是乙個記憶體位址,&運算子的作用也是取變數的記憶體位址,請看下面的**:
#include#include
int a = 1, b = 255;
int main()
在 c-free 5.0 下執行,結果為:
pa = 0x402000, &b = 0x402004
**中的 a、b 是全域性變數,它們的記憶體位址在鏈結時就已經決定了,以後再也不能改變,該程式無論在何時執行,結果都是一樣的。
那麼問題來了,如果物理記憶體中的這兩個位址被其他程式占用了怎麼辦,我們的程式豈不是無法執行了?
幸運的是,這些記憶體位址都是假的,不是真實的物理記憶體位址,而是虛擬位址。虛擬位址通過cpu的轉換才能對應到實體地址,而且每次程式執行時,作業系統都會重新安排虛擬位址和實體地址的對應關係,哪一段物理記憶體空閒就使用哪一段。如下圖所示:
虛擬位址的整個想法是這樣的:把程式給出的位址看做是一種虛擬位址(virtual address),然後通過某些對映的方法,將這個虛擬位址轉換成實際的實體地址。這樣,只要我們能夠妥善地控制這個虛擬位址到實體地址的對映過程,就可以保證程式每次執行時都可以使用相同的位址。
例如,上面**中變數 a 的位址是 0x402000,第一次執行時它對應的物理記憶體位址可能是 0x12ed90aa,第二次執行時可能又對應 0xed90,而我們的程式不需要關心這些,這些繁雜的記憶體管理工作交給作業系統處理即可。
讓我們回到程式的執行本質上來。使用者程式在執行時不希望介入到這些複雜的記憶體管理過程中,作為普通的程式,它需要的是乙個簡單的執行環境,有自己的記憶體,有自己的cpu,好像整個程式占有整個計算機而不用關心其他的程式。
除了在程式設計時可以使用固定的記憶體位址,給程式設計師帶來方便外,使用虛擬位址還能夠使不同程式的位址空間相互隔離,提高記憶體使用效率。
使不同程式的位址空間相互隔離
如果所有程式都直接使用物理記憶體,那麼程式所使用的位址空間不是相互隔離的。惡意程式可以很容易改寫其他程式的記憶體資料,以達到破壞的目的;有些非惡意、但是有 bug 的程式也可能會不小心修改其他程式的資料,導致其他程式崩潰。
這對於需要安全穩定的計算機環境的使用者來說是不能容忍的,使用者希望他在使用計算機的時候,其中乙個任務失敗了,至少不會影響其他任務。
使用了虛擬位址後,程式a和程式b雖然都可以訪問同乙個位址,但它們對應的實體地址是不同的,無論如何操作,都不會修改對方的記憶體。
提高記憶體使用效率
使用虛擬位址後,作業系統會更多地介入到記憶體管理工作中,這使得控制記憶體許可權成為可能。例如,我們希望儲存資料的記憶體沒有執行許可權,儲存**的記憶體沒有修改許可權,作業系統占用的記憶體普通程式沒有讀取許可權等。
另外,當物理記憶體不足時,作業系統能夠更加靈活地控制換入換出的粒度,磁碟 i/o 是非常耗時的工作,這能夠從很大程度上提高程式效能。
以上兩點我們將在《記憶體分頁機制》和《記憶體分頁機制的實現》中進行詳細講解。
在計算機中,為了讓操作更加直觀、易於理解、增強使用者體驗,開發者經常會使用一件法寶——增加中間層,即使用一種間接的方式來遮蔽複雜的底層細節,只給使用者提供簡單的介面。虛擬位址是使用中間層的乙個典型例子。
實際上,計算機的整個發展過程就是不斷引入新的中間層:
**:
C語言中使用的詞彙
在c語言中使用的詞彙分為6類 識別符號,關鍵字,運算子,分隔符,常量,注釋符等。一 識別符號。在程式中使用的變數名,函式名,標號等統稱為識別符號。c規定,識別符號只能是字母 數字 下劃線組成的字串,並且其第乙個字元必須是字母或下劃線。在識別符號中,大小寫是有區別的。二 關鍵字 ansi c關鍵字32...
什麼是C語言中的runtime?
大體來說,runtime是與runtime library密不可分的,這些庫依賴於特定的執行平台。按照wiki上的說法 在計算機程式設計中,runtime library執行時庫,是指一種被編譯器用來實現程式語言內建函式一提供該語言執行時 執行時 支援的一種特殊的計算機程式庫,這種庫一般包括基本的輸...
c語言中的「巨集」是指什麼?
簡單來說 巨集定義又稱為巨集代換 巨集替換,簡稱 巨集 是c提供的三種預處理功能的其中一種。複雜的請看下面,講的很全。下面的帶參巨集定義,多行巨集定義,在linux核心原始碼中很多。另外sizeof也是乙個巨集定義。巨集定義巨集定義是c提供的三種預處理功能的其中一種,這三種預處理包括 巨集定義 檔案...