儲存類

儲存類說明符是可以出現在宣告的頂級型別旁邊的關鍵字。這些關鍵字的使用會影響已宣告物件的儲存持續時間和連結,具體取決於它是在檔案範圍還是在塊範圍內宣告:

關鍵詞 儲存持續時間 連鎖 備註
static 靜態的 內部 為檔案範圍內的物件設定內部連結; 為塊範圍內的物件設定靜態儲存持續時間。
extern 靜態的 外部 對於在檔案範圍中定義的物件(也具有初始化程式)隱含且因此是冗餘的。當在沒有初始化程式的檔案範圍的宣告中使用時,提示該定義將在另一個翻譯單元中找到,並將在連結時解析。
auto 自動 不相干 隱含,因此對於在塊範圍內宣告的物件是多餘的。
register 自動 不相干 僅與具有自動儲存持續時間的物件相關。提供變數應儲存在暫存器中的提示。強加的約束是不能在這樣的物件上使用一元 &地址運算子,因此該物件不能被別名化。
typedef 不相干 不相干 在實踐中不是儲存類說明符,但從語法的角度來看就像一個。唯一的區別是宣告的識別符號是一個型別,而不是一個物件。
_Thread_local 內部外部 在 C11 中引入,表示執行緒儲存持續時間。如果在塊範圍內使用,它還應包括 externstatic

每個物件都有一個相關的儲存持續時間(無論範圍如何)和連結(僅與檔案範圍內的宣告相關),即使省略了這些關鍵字也是如此。

關於頂級型別說明符(intunsignedshort 等)和頂級型別限定符(constvolatile)的儲存類說明符的順序未強制執行,因此這兩個宣告都是有效的:

int static const unsigned a = 5; /* bad practice */
static const unsigned int b = 5; /* good practice */

但是,將儲存類說明符放在首位,然後是任何型別限定符,然後是型別說明符(voidcharintsigned longunsigned long longlong double ……),這被認為是一種好習慣。

並非所有儲存類說明符在某個範圍內都是合法的:

register int x; /* legal at block scope, illegal at file scope */
auto int y; /* same */

static int z; /* legal at both file and block scope */
extern int a; /* same */

extern int b = 5; /* legal and redundant at file scope, illegal at block scope */

/* legal because typedef is treated like a storage class specifier syntactically */
int typedef new_type_name;

儲存持續時間

儲存持續時間可以是靜態的或自動的。對於宣告的物件,根據其範圍和儲存類說明符確定。

靜態儲存持續時間

具有靜態儲存持續時間的變數在整個程式執行期間都存在,並且可以在檔案範圍(有或沒有 static)和塊範圍(通過明確地放置 static)宣告。它們通常在程式啟動時由作業系統分配和初始化,並在程序終止時回收。在實踐中,可執行格式具有用於這些變數的專用部分(databssrodata),並且來自檔案的這些整個部分被對映到特定範圍的儲存器中。

執行緒儲存持續時間

Version => C11

此儲存持續時間在 C11 中引入。這在早期的 C 標準中是不可用的。一些編譯器提供具有類似語義的非標準擴充套件。例如,gcc 支援 __thread 說明符,可以在早期的 C 標準中使用,它沒有 _Thread_local

具有執行緒儲存持續時間的變數可以在檔案範圍和塊範圍內宣告。如果在塊範圍內宣告,它還應使用 staticextern 儲存說明符。它的生命週期是整個執行它建立它的執行緒。這是唯一可以與另一個儲存說明符一起出現的儲存說明符。

自動儲存持續時間

具有自動儲存持續時間的變數只能在塊範圍內宣告(直接在函式內或在該函式的塊內)。它們僅在進入和離開功能或塊之間的時間段內可用。一旦變數超出範圍(通過從函式返回或離開塊),它的儲存將自動解除分配。從指標對同一變數的任何進一步引用都是無效的,並導致未定義的行為。

在典型的實現中,自動變數位於函式的堆疊幀中或暫存器中的某些偏移處。

外部和內部聯絡

連結僅與在檔案範圍內宣告的物件(函式和變數)相關,並影響它們在不同翻譯單元中的可見性。具有外部連結的物件在每個其他翻譯單元中都可見(前提是包含適當的宣告)。具有內部連結的物件不會暴露給其他翻譯單元,只能在定義它們的翻譯單元中使用。