C++內存模型

1、存儲持續性

C++使用四種不同方案來存儲數據,它們的區別在於數據在內存中保留的時間,也叫做存儲持續性

(1)自動存儲持續性

  在函數定義中聲明的變量,包括函數參數。

(2)靜態存儲持續性

  在函數定義外和使用關鍵字static定義的變量。它們在程序整個運行過程中都存在。

(3)線程存儲持續性

  在C++11中,如果使用關鍵字thread_local聲明變量,則變量生命期和所屬線程一樣長。

(4)動態存儲持續性

  使用new運算符分配內存的數據。

2、作用域和鏈接性

作用域描述了名稱在文件的多大範圍內可見。包括函數定義或者代碼塊內可見、當前文件內可見和整個程序可見。鏈接性描述了名稱如何在不同單元間共享。鏈接性爲外部的名稱可在文件間共享,鏈接性爲內部的名稱只能在當前文件中共享。自動變量的名稱沒有鏈接性,因爲它們不能共享。作用域和鏈接性的意思一樣。

3、靜態存儲持續性變量的作用域和鏈接性

靜態存儲持續性地變量在程序運行過程中在內存中都存在,靜態變量默認被初始化爲0,包括三種作用域和鏈接性

(1)外部鏈接性(作用域爲整個程序)

在函數或者代碼塊外面聲明的變量,也稱爲外部變量

(2)內部鏈接性(作用域爲當前文件)

在函數或者代碼塊外面聲明,並且使用static限定符的變量

(3)無鏈接性(作用域爲當前函數或者代碼塊)

在函數或者代碼塊內部聲明,並且使用static限定符的變量

4、單定義規則

同一個變量,只能有一次定義和初始化。C++提供了兩種變量聲明,一種爲定義聲明(defining declaration),簡稱定義,它爲變量分配存儲空間;一種爲引用聲明(referencing declaration),簡稱聲明,它不給變量分配存儲空間。引用聲明使用關鍵字extern。外部鏈接性變量可以在頭文件中進行聲明,在源文件中進行定義和初始化,其他文件只要引用該頭文件即可以訪問該變量。內部鏈接性變量一般在源文件中定義變量,但是在頭文件中定義變量也不影響,因爲它的作用域爲當前文件,如果兩個源文件都引用該頭文件,那麼在兩個文件中都將分別定義一個變量,分配兩塊內存。

5、const外部變量

默認情況下全局變量的鏈接性爲外部的,加上const修飾符後,鏈接性爲內部的。如果希望const修飾的常量鏈接性爲外部的,則使用extern來修飾,例如extern const int i = 10。和外部變量不同,外部常量定義和聲明必須都加extern修飾符。

6、函數和鏈接性

函數的存儲持續性爲靜態的,鏈接性默認爲外部的。可以在源文件中定義函數,在頭文件中使用extern聲明函數,當然extern可以省略。需要在函數定義和聲明添加static關鍵字將函數的鏈接性變爲內部的。非內聯函數默認也要滿足單定義規則,內聯函數不受這一約束。

7、語言的鏈接性

鏈接程序要求每個函數都有不同的符號名。在C語言中,一個名稱只對應一個函數,很容易實現。一般C語言編譯器可能將fun這樣的函數翻譯爲_fun。這種方法被稱爲C語言鏈接性。C++語言因爲重載的使用,一個名稱可以對應多個函數。C++編譯器需要執行名稱矯正或者名稱修飾,爲重載函數生成不同的符號名。例如,可能將fun(int)轉換爲_fun_i,將fun(double,double)轉換爲_fun_d_d,這種方法被稱爲C++語言鏈接性。如果在C++語言中使用C語言編譯的庫,則因爲語言鏈接性不同,鏈接器無法尋找正確的函數符號,需要指定鏈接器按照C語言鏈接性去尋找函數符號。例如:

extern "C" void fun(int);

一般如果編譯的C庫不僅供C程序調用,也供C++程序使用,可以在C庫頭文件中添加如下代碼

#ifdef __cplusplus       //如果採用了C++,如下代碼使用C編譯器
    extern "C" {            //在C語言中添加extern "C"會報錯,因爲這是C++語言的語法
#endif
/*C語言頭文件*/
#ifdef __cplusplus      //結束使用C編譯器
    }
#endif   

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章