轉載 http://blog.csdn.net/leaf1984zh/article/details/5964256
C語言之作用域在C語言中,涉及到作用域和生存周期的問題,大多是指的變量和函數。C語言中用得最多的應當算是局部變量了,而局部變量的作用域一般認為在函數體內有效。局部變量的內存分配管理和銷毀是由編譯器來實現的,程序編寫者不用考慮其實現細節。當函數執行完成返回時,局部變量將全部被銷毀,這決定了其生存周期。這里涉及到返回值的問題,至于是在返回值傳遞完成之后銷毀呢,還是將返回值拷貝到一個臨時變量中,銷毀全部的局部變量,再將臨時變量返回呢,這是由編譯器的設計者所決定的。目前大多數的C編譯器是采用的后者的設計方案。剛剛提到局部變量的作用域一般認為是在函數體內。但是根據C99標準,該說法有了變化。在新的標準中,允許即時定義局部變量,示例如下:for( int i = 0; i < MAXSIZE; i++ ){….}例子中的局部變量i的作用域即在for循環的花括號中,當for循環結束的時候,局部變量i的生存周期同時結束。也就是說,在下一個for循環中,你仍然可以再次重新定義并使用名為i的局部變量。該語法只能在C99之后的新的C編譯器中使用, 例如VC2005、VC2008、gcc4.2及以上版本。但是,該語法帶來了編程風格的變化,而且變量隱含在了執行程序中,無論是代碼的閱讀和維護都有較大的困難,因此工程項目中不建議使用該語法。程序代碼,是為了方便別人閱讀而寫的,而不是只有自己能夠閱讀。只有自己才能讀得懂的代碼,是沒有使用價值的。函數退出時被銷毀的局部變量包括整型、浮點型、數組、函數體中定義的指針(指針,對于編譯器來說,它看到的依然是一個整型的變量而已)。肯定有人會問到,如果想要函數體中的局部變量在函數退出時不被銷毀,那該怎么辦呢?其實這也簡單,你只需要在定義的局部變量的前面加上static關鍵字,將其聲明為靜態變量即可。注意,靜態變量的初始化只有一次,也就是當函數第一次被調用的時候將對靜態變量進行初始化,之后類似于int i = 0這樣的語句將會失效。一旦聲明為靜態變量,程序沒有退出,靜態變量將一直存在。使用靜態變量的時候,一定要清楚為什么要使用靜態變量,而不是僅僅為了某次操作,能夠方便取得函數體中的某個變量的值而已。雖然其生存周期發生變化了,但是它的作用域依然限制在函數體的范圍內。把變量定義在函數體外,就是全局變量。全局變量的生命周期等同于程序執行時間,程序開始執行時,全局變量將被執行初始化(這與靜態變量不同,靜態變量是執行函數時才初始化的)。全局變量的優勢就是,你可以在任何時候,任何函數中方便的訪問到,實現數據共享。但同時,也存在共享數據被篡改的可能,尤其是多線程操作的時候,必須對每次操作進行加鎖。在默認狀態下,全局變量可以被工程項目中的任何文件和函數訪問。但是,不同文件有所區別。如果是在定義全局變量的c文件中,無需聲明就可以使用該變量;其他的c文件中,只需使用extern關鍵字進行聲明(不是定義),即可使用。聲明時,不能對全局變量進行賦值操作。全局變量一般不在h頭文件中定義,容易發生重定義錯誤。extern int i ; 在C語言中,函數被默認為是全局的,只要在頭文件中進行了聲明,你可以在工程中的任何位置使用。在h頭文件中,聲明為int Foo(); 和extern int Foo(); 其實質是一樣的。除此之外,你還可以將函數冠以static關鍵字,將其定義為靜態函數。其意義在于,更改了函數的作用范圍。聲明為static的函數,只能在定義該函數體的c文件中使用,其他位置的程序段無法使用聲明為static的函數。由于作用域的范圍沒有沖突,于是,你可以定義與聲明為static同名的另一個函數,至于這個函數是全局的,還是靜態的,無關緊要。因為在定義了同名的static函數的c文件中,編譯器只會使用標記有static的函數,而忽略外部的全局函數。很少討論函數的生存周期,因為函數執行完成退出時,被認為其生命周期的結束。就算該函數再次被調用,那也是新的生存周期。另外,C語言中還有auto關鍵字,其實那更多的是編譯器自己在用,而對于程序編寫者來說,可以忽略掉。 大多數的書籍和文章對變量和函數的討論也就到此結束了。而我想在這里談論一下其他的幾個方面: 宏定義C語言中的宏定義是一個偉大的創新,也被稱作是個愚蠢的設計。其實宏定義在程序的編譯階段就完成了,因此也就不存在生命周期這回事。通常宏定義出現在h頭文件之中,也就是說只要你包含了這個頭文件,你就可以用宏定義了;如果是定義在c文件之中的,那就只能在該c文件中使用了。 結構體工程項目中,通常都是使用公共結構體來實現不同函數(或者功能模塊)間的數據傳遞。公共結構體一般定義在外層的h頭文件中。至于你要將其實例化為全局變量,還是局部變量,那需根據實際情況而定。 內存管理前面提到的局部變量內存空間的申請銷毀,是由編譯器實現的。而使用malloc函數進行動態分配的內存空間,才需要使用free函數手動釋放。關于內存分配管理很多中文書本都略過不談,為什么呢?因為寫書的人自己都沒弄明白,結果給很多人帶來困惑。或許這本身確實很復雜,但卻可以簡單的解釋下。原則上,一個程序能夠使用的內存的范圍是操作系統分配給程序的那部分。而這部分內存將隨程序的退出而返還給操作系統。那么free執行的操作是什么呢?free函數釋放的內存空間,實際上是釋放給了程序本身,而不是操作系統。釋放的空間可以再次分配給程序的其他函數體使用,而不需要再向操作系統申請,操作系統一般也不能夠隨便收回程序所正在使用的內存空間。(如果能夠,那需要操作系統和編譯器的支持才行。)程序使用free釋放的內存空間,是程序的所有函數體所共享的。底層操作均由編譯器實現,不需要程序編寫者考慮。說簡單點,malloc首先要求分配內存,若程序中剩余空間不能滿足,就向操作系統要資源,用完了后不把這部分資源還給操作系統,直到程序的退出,操作系統才能對內存進行回收。這就是為什么程序占用內存始終是越來越多。
新聞熱點
疑難解答