[語法] 作用範圍(scope) 與 生命期(lifetime)

看板C_and_CPP (C/C++)作者時間17年前 (2007/04/12 06:03), 編輯推噓7(701)
留言8則, 8人參與, 最新討論串1/1
最近想把程式寫的有系統一點, 就研究了一下變數儲存等級(storage class) 想說把心得整理成筆記, 順便分享給大家~ 下面討論的主要以 C語言 為主 1. 區塊 (block) 例如: { .... } 區塊就是任何以大括號包起來的區域, 如函式區塊, if區塊, for區塊 嚴格說起來, 在任何 statement 出現之前, 一定要把 block 內使用到的變數定義好 在 block 外定義的變數就是 global variable 在 block 內定義的變數就是 local variable 在 block 內想要使用不在 scope 裡的 global variable, 就要用 extern 宣告此變數 在 block 外想要使用 local variable, 很可惜, C語言沒有支援這種功能 在 block 內定義的變數, 會遮蔽 block 外定義的變數 2. 宣告 (declaration) 例如: (auto) int a; // in block, 定義 + 宣告 int a; // out block, 定義 + 宣告 extern int a; // out block, 宣告 宣告主要是告訴 compiler 說 "這個變數之前有定義過了, 我現在要用這個變數囉" 如果配合儲存等級, 就是說 "此變數的 scope 和 lifetime 是如 keyword 所指定的" 如果變數使用前沒有先宣告, 會有 undeclare 的錯誤 我覺得宣告最主要的作用就是把變數的 scope 和 lifetime 定出來 3. 定義 (definition) 例如: (auto) int a; // in block, 定義 + 宣告 int a; // out block, 定義 + 宣告 extern int a = 0; // out block, 定義 + 宣告 (其實 extern 是多餘的) 定義就是 memory or stack 配一個空間給變數, 一個變數當然只能有一個空間 local auto variable 是在 run-time 的時候由 stack 配給空間, 初值是隨機給的 其他的情況, 則是在程式開始執行的時候就佔有 memory 的空間, 初值是0 local static variable 如 { static int a = 5; } 只會在第一次定義時給初值 之後再碰到此敘述時, 會將其視為宣告, 而不會再做初始化的動作 定義有宣告的效果, 但是宣告沒有定義的效果 在同一個 scope 裡面, 定義只能有一次, 宣告則可以有很多次 例外: int a; { int a; } 雖然第一個 int a; 的 scope 有觸及到 block 裡面 但是第二個 int a; 把第一個 int a; 的效果遮蔽掉了, 所以不能算定義兩次 如果變數在同一個 scope 裡定義兩次以上, 會有 redefine 的錯誤 如果變數只有宣告而沒有定義, 會有 undefine 的錯誤 4. 作用範圍 (scope) 作用範圍就是一個變數能觸及到的視野, 在變數的 scope 裡, 使用該變數都有效 每種 storage class 都有其自然視野(natural scope) 想要擴展變數的 scope, 就要使用 extern 宣告來增加其腹地 自然視野大致可分為 block scope, file scope 兩種 block scope 就是從變數宣告開始, 到 block 結束為止 file scope 就是從變數宣告開始, 到 file 結束為止 會發生 undeclare 的錯誤, 就是因為沒在某變數的 scope 裡使用該變數 5. 生命期 (lifetime) 生命期就是一個變數生存的時間, 當變數的 lifetime 過了 則這個變數就完全無效了, memory 裡的空間也就 free 掉了, 即使再宣告也沒用 會發生 undefine 的錯誤, 就是因為沒在某變數的 lifetime 裡使用該變數 會發生 redefine 的錯誤, 就是因為兩個同名的變數, 在同一時期生活在一起 這邊同樣要注意 block 的遮蔽效果, 可以讓兩個同名的變數生活在不同的世界 變數的生命期分兩種 一種是 local auto variable, 其生命期是從 stack 配空間開始, 到 block 結束為止 其他的情況, 都是從程式執行開始, 到程式結束為止 6. 儲存等級 (storage class) 儲存等級的 keyword: auto, static, extern, register 這邊不討論 register, 因為現在的 compiler 有時候比人還強, 比人更了解底層機器 而 extern 主要只是搭配 global variable 去拓展 scope 而已 剩下的兩個 keyword (auto, static), 再配上 block 的觀念, 只剩四種可能 | | | in/out block | keyword | natural scope | lifetime | | | ======================================================================== | | | | (auto) int a; | block scope | to block end | | | local ---------------------------------------------------------- | | | | static int a; | block scope | whole program | | | ------------------------------------------------------------------------ | | | | int a; | file scope | whole program | | | global ---------------------------------------------------------- | | | | static int a; | file scope | whole program | | (strictly) | ------------------------------------------------------------------------ ※ static 在 local variable 的作用是改變 lifetime ※ static 在 global variable 的作用是影響 scope 擴展的限制 如果 global variable 沒有加 static 修飾, 則可以用 extern 跨 file 宣告 如果 global variable 有使用 static 修飾, 則不能用 extern 跨 file 宣告 所以利用 static 可以做到變數封裝的效果, 也就是 C++ class 的效果 ※ extern 只對 global variable 有作用而已 ※ 若在 block 內使用 extern, 則所增加的 scope 為 block scope 若在 block 外使用 extern, 則所增加的 scope 為 file scope 7. 函式 (function) 函式也是一個外在個體, 可以完全視為一個 global variable 以上所有適用於 global variable 的條例, 都適用於 function 8. 動態記憶體配置 (dynamic memory allocation) 動態記憶體配置一般是由 malloc 以及 free 這一對 C library function call 完成 最大的好處在於可以自由的指定配置時機, 以及自由的指定配置空間 動態記憶體配置只是一個經由 system call 向 OS 要記憶體的方式 所以它沒有宣告和定義的行為, 當然也沒有 lifetime 和 scope 的觀念 因此配置的空間從 malloc 開始, 到 free 掉為止, 都存在著 只要有指標指向這個空間, 就可以去存取, 一次存取的大小以指標的 data type 決定 而釋放記憶體空間時, 只要有指標指向這段空間的開頭, 再用 free 即可 9. 編譯 (compile) 編譯的時候, 是一次 compile 一個 file, 就算再怎麼大的程式 compiler 一次也只看一個檔案, 頂多先把一些 global variable 定義記起來 等到 link 階段的時候, 看看會不會有 redefine or undefine 的情況 所以要寫一個大程式, 只要注意幾件事 (1) 整個 program 裡面, 每個 global variable 都有定義, 而且只有定義一次 (2) 每個 file 裡面, 任何一個變數在使用前, 都有先宣告過 (3) 使用 local auto variable 時, 要注意其 lifetime (4) 使用 extern 時, 該變數在別的地方要有定義 (5) 在 block 內可以利用 static 來增加 lifetime (6) 在 block 外可以利用 static 來封裝資料 (7) 要注意 block 的遮蔽效果 (8) 在 .h 檔裡面, 要使用 ifndef, define 等條件式編譯, 避免 redefine 的情況 大概就是這些重點囉, 如果有什麼地方的觀念有錯, 歡迎大家指正, 謝謝~ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.29.206

04/12 09:31, , 1F
推,整理的不錯
04/12 09:31, 1F

04/12 10:30, , 2F
推~
04/12 10:30, 2F

04/12 15:20, , 3F
那static function呢?有人寫我無法體會用意~
04/12 15:20, 3F

04/12 21:14, , 4F
static function只能在同一個file裡的function被呼叫
04/12 21:14, 4F

04/13 04:31, , 5F
有關scope的部分現在似乎都交給namespace去做而少用static
04/13 04:31, 5F

04/13 17:08, , 6F
推 有很多很有用的觀念~
04/13 17:08, 6F
※ 編輯: shyang55 來自: 140.112.29.206 (04/16 03:04)

10/20 21:28, , 7F
推 借轉XD
10/20 21:28, 7F

04/12 09:49, , 8F
好文借轉
04/12 09:49, 8F
文章代碼(AID): #167Lisxo (C_and_CPP)
文章代碼(AID): #167Lisxo (C_and_CPP)