從編譯原理來看引用型別和值型別

2021-04-17 13:17:56 字數 1647 閱讀 4611

看了好多書,研究了下值型別和引用型別,總是有種模稜兩可的感覺,這讓我萌發了,大眾角度主要是分析記憶體中的東西,而我準備從記憶體和編譯原理兩個方面來入手,本人先說明我沒學過編譯原理,但略讀了下,發現用這個來解釋更好。參考《程式設計編譯原理》這本書,我不知道vs ide的編譯工具是採用什麼編譯原理的,但大體的猜了下,應該和這個差不多。

每個編譯器都有各自的符號表,用來儲存所有識別符號(變數名,常量名等)

我是根據c語言來思考c#當中的兩種型別

c語言源程式到.exe可執行程式的轉換需要經過好多步驟。其中就有編譯一步。而在編譯這一步,有細分為好幾小步。我記得不是很清楚,好想有什麼詞法分析,語法分析,名稱表生成,**優化,等等等等。   

在編譯過程中,當系統發現你定義了乙個變數並給它賦了初值,就會給該變數分配相應的儲存空間,並把該變數的名稱和儲存空間的第乙個位元組的位址存在乙個變數名表裡。由該變數的型別可以知道該變數佔據的儲存空間大小。所有的變數都一樣。   

以後要使用某乙個變數的時候,便會到變數名表裡查該變數的名字,要是沒找到,表示沒有定義該變數,提示錯誤;要是找到了,就會知道該變數的儲存空間位址了,如是就到該儲存空間裡把變數的值取出來。   

這就是使用變數的乙個過程。其中生成變數名錶的過程是在編譯的過程形成的。   

所以說:使用變數,就是通過變數名,訪問變數儲存空間裡的值,也就是變數的值。

變數分為變數名和變數值

注意這裡只看變數名,變數名是儲存在棧符號表中的,符號表說白了就是乙個檔案,而這個檔案也佔記憶體,在記憶體中是用棧來儲存其中的資訊的

名稱

相關資訊

相對位址

變數型別(所有值型別和引用型別)

種屬(簡單變數,類,結構,陣列等)也就是隸屬於什麼

長度(所需的儲存單元數)

若為陣列 記錄其內情向量

其它的不怎麼重要就不寫了

隨著變數的定義,同時生成自己的儲存單元,相對位址也就是自己的位址 如 int a,同時建立a儲存單元,這些都是在記憶體中的堆疊產生的。然後賦值給a儲存單元,則相對位址就是a儲存單元的這個位址。

不會隨著變數定義而同時生成自己的儲存單元,所以與符號表中對應的位址是你賦值給它的那個位址,預設是null,也就是相對位址為null 如 form f=new form(); 這個f是個變數名,儲存在變數名錶中,變數宣告的時候沒有自動生成自己的儲存單元,也就是儲存變數值的地方,所以它是用來引用乙個儲存單元的,在棧中儲存它是引用位址,並在編譯的時候將它寫入變數名錶中的相對位址,這裡就是new form()在堆中的記憶體位址,注意new分配空間是在堆中分配空間的位址

關於form f=null的討論

1、曾使用過f,然後才讓f   =   null;的話。在堆裡面不佔空間。而在棧裡面,還是要占用一些空間的。這個空間原來存放的是對原有的物件的引用(reference),現在為null了。  

2、未使用過a,直接寫a   =   null;這樣的話,在棧裡面也要佔空間的。堆裡不占用。  

值型別的 在變數名錶當中的相對位址,當宣告變數的時候,已經固定不變了,棧中儲存單元是儲存賦給的值,相對位址是棧中儲存單元的位址。

引用型別 在變數名錶當中的相對位址,會不段隨著引用的不同,而不段發生變化,棧中儲存的引用位址

關鍵的地方:

右值和左值(適用於值型別和引用型別):

引用型別和值型別

c 是一種型別安全的語言。每乙個變數都要求定義為乙個特定的型別,並且要求儲存在變數中的值只能是這種型別的值。變數既能儲存值型別,也可以儲存引用型別,還可以是指標。這一課將講述前兩種型別,關於指標的討論我們將在下一課中進行。下面是關於值型別和引用型別不同點的概論 如果乙個變數v儲存的是值型別,則它直接...

引用型別和值型別

c 中值型別和引用型別作為方法引數傳遞的時候其實都可以說是 值 的傳遞,只不過這裡的 值 指代的東西有所區別。當方法的引數為值型別時,方法傳遞的是值本身的值。當方法的引數為引用型別時,方法傳遞的則是應用型別的引用的位址,也就是引用型別位址在棧上的值。舉個引用型別作為引數傳遞的例子 static vo...

值型別和引用型別

為了更好地說明兩種型別之間的區別,借用如下的 來說明 值型別引用型別 記憶體分配地點 分配在棧中 分配在堆中 效率效率高,不需要位址轉換 效率低,需要進行位址轉換 記憶體 使用完後,立即 使用完後,不是立即 等待gc 賦值操作 進行複製,建立乙個同值新物件 只是對原有物件的引用 函式引數與返回值 是...