1. 程式人生 > >[C++] 資料的儲存方式

[C++] 資料的儲存方式

C++中儲存方式是通過儲存持續性,連結性和作用域來描述的。

1.儲存持續性

儲存持續性是指變數在記憶體中保留的時間,C++中共提供了四種持續性:

  • 1.自動儲存持續性:在函式中或程式碼塊中定義的變數,其儲存持續性為自動持續儲存;
  • 2.靜態儲存持續性:在函式外定義的變數和使用關鍵字static定義的變數,其儲存持續性為靜態持續儲存;
  • 3.動態儲存持續性:使用new關鍵字分配記憶體的變數,其儲存性為動態儲存持續;
  • 4.執行緒儲存持續性:C++11中提供,由關鍵字thread_local指出變數的持續性和當前執行緒持續性相同。

2.作用域

作用域描述了變數在檔案中的可見範圍,函式中定義的變數僅僅可在該函式中使用,檔案中定義的變數可在所有函式中使用。

3.連結性

連結性決定了是否可以在不同檔案中進行共享,有三種連結性:

  • 外部連結性:可在其他檔案中訪問;
  • 內部連結性:當前檔案中訪問;
  • 無連結性:當前函式和程式碼塊中訪問;

變數的儲存方式

1.自動變數

儲存持續性為自動儲存持續性、作用域為區域性、無連結性的變數,稱為自動變數。因此自動變數也是區域性變數的一種。在函式內部、程式碼塊中定義的變數都為自動變數。自動變數儲存於棧中。

在c++11中,auto關鍵字用於自動型別推斷,但是在c++98中,其含義宣告自動變數,這種做法很少使用,因此,c++11中對auto賦予了全新的含義。

在c++11中,對關鍵字register也做了改變。原本register

表示使用CPU暫存器來儲存自動變數,c++11中,register表示顯式地聲明瞭自動變數。

2.靜態持續變數

和自動變數儲存於棧中不同,編譯器為靜態變數分配固定的記憶體來儲存所有的靜態變數。靜態持續變數有三種:

3.1.靜態持續性+外部連結性(外部變數)

儲存持續性為靜態,連結性為外部,作用域為整個檔案。這種變數也稱為外部變數。

3.1.1.extern關鍵字

c++中規定,在每個使用外部變數的檔案中,都必須宣告它,但是又根據單定義規則,變數只能定義一次。因此,c++提供了兩種變數宣告:

  • 1.定義:給變數分配記憶體空間;
  • 2.宣告:使用extern關鍵字,表示不給變數分配記憶體空間,引用已有的變數。

所以,如果要在多個檔案中使用外部變數,只需要在一個檔案中定義該變數,在使用該變數的檔案中,使用extern關鍵字宣告它,如下示例:

//extern1.cpp
#include <iostream>

int global = 100;

//extern2.cpp
#include <iostream>

using namespace std;

extern int global;
int main()
{
        cout << "global:" <<global << endl;
        return 0;
}

對這兩個檔案進行編譯後,執行結果如下:

@ubuntu:~/workspace/C++/chapter8$ g++ extern1.cpp extern2.cpp -o exter
@ubuntu:~/workspace/C++/chapter8$ ./exter 
:100
@ubuntu:~/workspace/C++/chapter8$ 

3.1.2.作用域解析符::使用外部變數

如果存在同名的外部變數和自動變數,則在自動變數作用域內,通過作用域解析符::來使用外部變數,如:

#include <iostream>

using namespace std;

int days = 20; 
void update();

int main()
{
        update();    
        return 0;
}

void update()
{
        int days  = 40; 
        cout << "local days = " << days << endl;
        cout << "global days = " << ::days << endl;
}
/*
local days = 40
global days = 20
*/

靜態持續性+內部連結性(全域性變數)

static限定符用於作用域為整個檔案的變數時,該變數的連結性變為內部連結性。
也就是說,對常規的外部變數使用static限定,將會使得該變數僅在當前檔案中可用。
如:

//file1.cpp
#include <iostream>

int age = 20; 
int weight = 40; 
void show();

int main()
{
        using namespace std;
        cout << "in main():" << endl;
        cout << "age: " << age << " ,address: " << &age << endl;
        cout << "weight: " << weight << " ,address: " << &weight << endl;
        show();
        return 0;
}

//file2.cpp
#include <iostream>

static int age = 50; 
extern int weight;

void show()
{
        using namespace std;
        cout << "in show():" << endl;
        cout << "age: " << age << " ,address: " << &age << endl;
        cout << "weight: " << weight << " ,address: " << &weight << endl; 
}

/*
in main():
age: 20 ,address: 0x601070
weight: 40 ,address: 0x601074
in show():
age: 50 ,address: 0x601078
weight: 40 ,address: 0x601074

*/

在兩個檔案中,定義了兩次age變數,但這並不違反單定義規則,因為static關鍵字指出,變數的連結性為內部,因此並非要提供外部定義。

const關鍵字對外部變數也有影響,如果外部變數用const限定,則其連結性將變為內部,就像使用了static一樣。

3.3.靜態持續性+無連結性(靜態區域性變數)

對於在函式體或者程式碼塊中定義的變數,為自動變數(儲存持續性為自動,作用域為當前程式碼塊,連結性無)。將static關鍵字用於該變數時,將會使該變數的儲存持續性變為靜態。這種變數也成為靜態區域性變數。

這意味著該變數只在當前程式碼塊中可用,但是當該程式碼塊執行完畢後,該變數仍然存在。

此外,程式只會對靜態區域性變數初始化一次。

static用於全域性變數是,改變其連結性(由外部連結性變為內部連結性);

static用於區域性變數時,改變其儲存持續性(由自動儲存持續性變為靜態儲存持續性).

4.儲存說明符和型別限定符

在以上提及的儲存方案中,提到了幾個關鍵字,這裡對它進行總結。

4.1.儲存說明符

C++中有五個儲存說明符:

auto

auto在c++11中不再是儲存說明符,C++11之前是之顯式地宣告一個自動變數,c++11中用於自動型別推斷。

register

register在c++11中也被賦予了新的含義,c++11之前是指將變數儲存在CPU暫存器中,c++11中是指顯式地宣告自動變數。

register僅對聲明於塊作用域和函式引數列表的物件允許。

static

static用於全域性變數是,改變其連結性(由外部連結性變為內部連結性);
static用於區域性變數時,改變其儲存持續性(由自動儲存持續性變為靜態儲存持續性).

extern

extern關鍵字用於引用宣告,由於c++規定,每個變數在檔案中必須宣告,由由於單定義規則的限制,不允許多次定義同一個變數,因此使用extern關鍵字引用其他檔案中定義的外部變數。

thread_local

thread_local在c++11中引入,只對聲明於名稱空間作用域的物件、聲明於塊作用域的物件及靜態資料成員允許。它指示物件擁有執行緒儲存期。它能與staticextern 結合,以分別指定內部或外部連結(除了靜態資料成員始終擁有外部連結),但附加的 static 不影響儲存期。

4.2.型別限定符

型別限定符有三種:

const

const關鍵字最常用,表示該型別為一個常量。關於const的使用已經非常多了,這裡來看下它對外部變數的一個影響。

const用於外部變數時,將會改變其連結性(由外連結性變為內連結性),如此一來,該變數將會僅僅在該檔案中共享。

如果希望某個常量的連結性為外部,則可以使用extern來覆蓋預設的內部連結性:

//file1.cpp
extern const int Size = 20;
//file2.cpp
extern const int Size;//或者extern int Size;

volatile

volatile關鍵字用來提醒編譯器,即使程式沒有修改變數,其值也可能發生變化。

在編譯器處理程式時,如果發現在多個語句中使用了某個變數多次時,可能會進行優化,於是會將該變數寄存到暫存器中,從而完成優化。正是由於這個原因,如果在程式沒有修改該變數時,其值發生了變化,那麼程式將無法獲取到新的值。

因此,將變數宣告為volatile,告訴編譯器,不要進行這種優化。

mutable

mutable關鍵字應用於非引用非const型別的非靜態類成員,並指定該成員不影響類的外部可見狀態(常用於互斥、記憶體快取、惰性求值、及訪問裝置)。
const類例項的mutable成員是可修改的。
如:

struct student
{
    std::string name;
    mutable int age;
};
const student s1 = {"zhangsan",12};
s1.age = 23;//OK

5.動態記憶體分配

使用new申請的記憶體和上述提到的自動記憶體和靜態記憶體分配有所不同,動態記憶體由newdelete控制,而不受作用域和連結性的控制。

關於動態記憶體分配,在如下文章中:

相關推薦

C語言變數定義與微控制器資料儲存方式

說明:文章來源 EDN電子技術設計:嵌入式程式開發需要知道的儲存器知識 MCU 中常使用的儲存器型別有:FLASH、RAM、ROM(包括EEPROM) 在軟體角度來看,程式和資料的儲存分為以下幾個部分 程式碼段和常量段都可以用於儲存常量資料,其主要區

C語言基本型別與其資料儲存方式

好久沒有更新部落格了,最近對逆向十分著迷,資訊保安的知識量是真的龐大,是時候該做一波筆記了,哈哈。 看下圖,C語言資料型別分為右邊四大型別,這篇部落格重點講基本型別,因為其他型別還沒學呢~~ 整數型別 資料型別分為 char short int long 四種 char 

11.1 js中級,資料型別、資料儲存方式、作用域記憶體空間的區別以及例識別。

一. 基本資料型別和引用資料型別的區別。     1.基本資料型別:基本資料型別就是簡單的操作值。     2.引用資料型別:就是把引用的地址賦給變數。   堆記憶體:     就是存放程式碼塊的,存放形式有兩種       1)物件以鍵值對的形式存放       2)引用資料型別的賦值,是把引用

Android 資料持久化技術(即資料儲存方式

在討論資料持久化技術之前我們先了解幾個概念? 什麼是瞬時資料:儲存在記憶體當中,有可能會因為程式的關閉或其他原因導致記憶體被收回而丟失的資料。   為什麼採用資料持久化技術:為了保證關鍵資料在程式退出時不被丟失。   什麼是資料持久化技術:將記憶體中的瞬時資料

Android五種資料儲存方式之SQLite資料庫儲存 載入SD卡資料庫 sql操作 事務 防止SQL注入

資料庫 前言 資料庫儲存 資料庫建立 內建儲存資料庫 外接儲存資料庫 編寫DAO 插入操作 更新操作 刪除操作 查詢操作

Android五種資料儲存方式之檔案儲存 內部儲存 外部儲存 檔案讀取儲存操作封裝

檔案儲存 前言 檔案儲存 記憶體 內部儲存 外部儲存 內部儲存操作 API 讀寫操作 外部儲存操作 公共目錄 私有目錄

ios應用資料儲存方式(偏好設定)-轉

一.簡單介紹 1.很多ios應用都支援偏好設定,比如儲存使用者名稱,密碼,字型大小等設定,ios提供了一套標準的解決方案來為應用加入偏好設定功能。 2.每個應用都有個NSUserDefaults例項,通過它來儲存偏好設定。比如,儲存使用者名稱,字型大小,是否自動登入。 3.儲存位

資料儲存方式之 TXT 文字

Java 操作檔案輸入流與輸出流,具體內容包括 File 類、檔案位元組流與字元流、緩衝流。最後以網路爬蟲實戰案例,講解其具體的使用方式。 輸入流、輸出流簡介 在 Java 中,流是從源到目的地的位元組的有序序列。Java 中有兩種基本的流——輸入流和輸出流。輸

用 python 寫爬蟲 爬取得資料儲存方式

mysql: 首先配置檔案: ITEM_PIPELINES = { firstbloodpro.pipelines.MysqlproPipeline:300},配置好管道 第二配置好所需要的使用者名稱等 HOST='localhost' POST=3306 USE

資料儲存方式與記憶體分配方式

資料儲存方式: 1、未初始化的全域性變數(.bss段) 2、初始化過的全域性變數(.data段) 3、常量資料(.rodata段) 4、程式碼(.text段) 5、棧(stack) 6、堆(heap) 記憶體分配方式: 1、從靜態儲存區域分配。記憶體在程式編譯時就已經

C資料儲存與提取

      在c語言中,不同型別的資料在記憶體中基本上沒有差異,那麼這些定義的型別的作用是啥呢?這些定義的型別是來改變編譯器對這些資料提取時的方式,下面讓我們來看一些經典例題!!   #include<stdio.h>

IOS的四種資料儲存方式及優劣

IOS有四種常用資料儲存方式: 第一種方法:用NSUserDefaults儲存配置資訊 NSUserDefaults被設計用來儲存裝置和應用的配置資訊,它通過一個工廠方法返回預設的、也是最常用到的例項物件。這個物件中儲存了系統中使用者的配置資訊,開發者可以通

Android五種資料儲存方式

1、分類 資料儲存在開發中是使用最頻繁的,Android平臺中實現資料儲存主要有5種方式,分別是: SQLite: SQLite是一個輕量級嵌入式資料庫,支援基本SQL語法,是常被採用的一種資料儲存方式。Android為此資料庫提供了一個名為SQLiteDatabase的類,

關注 Linux c/c++ 資料儲存 網路 演算法......

Merkle Hash Tree 簡介 上圖(來自Wikipedia[1])給出了一個二進位制的雜湊樹(二叉雜湊樹, 較常用的tiger hash tree也是這個形式). 據稱雜湊樹經常應用在一些分散式系統或者分散式儲存中的反熵機制(Anti-entropy),也

Android中常用的五種資料儲存方式

第一種: 使用SharedPreferences儲存資料 適用範圍: 儲存少量的資料,且這些資料的格式非常簡單:字串型、基本型別的值。比如應用程式的各種配置資訊(如是否開啟音效、是否使用震動效果、小遊戲的玩家積分等),解鎖口 令密碼等 核心原理: 儲存基

安卓中五種資料儲存方式

分別是: --SharedPreferences儲存; --檔案儲存; --SQLite資料庫儲存; --ContentProvider儲存; --網路儲存; 1.1. SharedPreferences儲存: 應用場景: 適用於儲存一些鍵值對,一般用來儲存配置資訊。 儲存

java中整型資料儲存方式(原碼,反碼,補碼)

轉自:https://blog.csdn.net/yuling112358/article/details/7838916 java中整型資料儲存時是以補碼的方式進行的。 1.何為原碼,反碼,補碼? 首先java中的整型數值都是有符號的,規定資料的二進位制形式第一位為符號位。0為正,1為

Python+不同的資料儲存方式比較

本文來探索一下python中提供的各種資料儲存格式的效能如何。主要以一個 ndarray 格式的資料進行處理分析。包括下面幾種方式: .bin格式, np.tofile() 和 np.fromfile() .npy格式,np.save() 和 np.load

Python中scrapy爬蟲框架的資料儲存方式(包含:圖片、檔案的下載)

注意:1、settings.py中ITEM_PIPELINES中數字代表執行順序(範圍是1-1000),引數需要提前配置在settings.py中(也可以直接放在函式中,這裡主要是放在settings.py中),同時settings.py需要配置開啟2、 process_it

C++資料儲存型別

和C語言一樣,C++也為靜態儲存持續性變數提供了3種連結性:外部連結性(可在其他檔案中訪問)、內部連結性(只能在當前檔案中訪問)和無連結性(只能在當前函式或程式碼中訪問)。這3種連結性都在整個程式執行期間存在,與自動變數相比,它們的壽命更長。由於靜態變數的數目在程式執行期間是不變的,因此程式不需要使用特殊的裝