名稱空間
變體
操作

儲存類說明符

來自 cppreference.com
< c‎ | 語言

指定物件和函式的儲存期連結

  • auto - 自動儲存期,無連結
  • register - 自動儲存期,無連結;此變數的地址不能被獲取
  • static - 靜態儲存期和內部連結(除非在塊作用域內)
  • extern - 靜態儲存期和外部連結(除非已宣告為內部連結)
  • _Thread_local(C23前)thread_local(C23起) - 執行緒儲存期
(C11 起)

目錄

[編輯] 解釋

儲存類說明符出現在宣告複合字面量表示式中(C23起)。最多可以使用一個說明符,但_Thread_local(C23前)thread_local(C23起)可以與staticextern結合以調整連結(C11起)。儲存類說明符決定它們宣告的名稱的兩個獨立屬性:儲存期連結

1) auto說明符只允許用於在塊作用域內宣告的物件(函式引數列表除外)。它指示自動儲存期和無連結,這些是這些型別宣告的預設值。
2) register說明符只允許用於在塊作用域內宣告的物件,包括函式引數列表。它指示自動儲存期和無連結(這是這些型別宣告的預設值),但此外提示最佳化器儘可能將此變數的值儲存在CPU暫存器中。無論是否進行此最佳化,宣告為register的變數不能用作取地址運算子的引數,不能使用_Alignas(C23前)alignas(C23起)(C11起),並且register陣列不能轉換為指標。
3) static說明符指定靜態儲存期(除非與_Thread_local結合)(C11起)和內部連結(除非在塊作用域中使用)。它可以在檔案作用域的函式和檔案作用域與塊作用域的變數中使用,但不能在函式引數列表中使用。
4) extern說明符指定靜態儲存期(除非與_Thread_local(C23前)thread_local(C23起)結合)(C11起)和外部連結。它可以在檔案作用域和塊作用域的函式和物件宣告中使用(不包括函式引數列表)。如果extern出現在一個已經用內部連結宣告的識別符號的重新宣告中,則連結保持內部。否則(如果之前的宣告是外部連結、無連結,或者不在作用域內),則連結是外部連結。
5) _Thread_local(C23前)thread_local(C23起)指示執行緒儲存期。它不能用於函式宣告。如果它用於物件宣告,則它必須出現在同一物件的所有宣告中。如果它用於塊作用域宣告,則它必須與staticextern結合以決定連結。
(C11 起)

如果沒有提供儲存類說明符,則預設值是

所有函式都為extern
檔案作用域的物件為extern
塊作用域的物件為auto

對於使用儲存類說明符宣告的任何結構體或聯合體,儲存期(而非連結)遞迴地應用於其成員。

塊作用域的函式宣告可以使用extern或不使用。檔案作用域的函式宣告可以使用externstatic

函式引數不能使用除register之外的任何儲存類說明符。請注意,static在陣列型別的函式引數中具有特殊含義。

[編輯] 儲存期

每個物件都有一個名為儲存期的屬性,它限制了物件的生命週期。C中有四種儲存期

  • 自動儲存期。當宣告物件的被進入時分配儲存,並在透過任何方式(gotoreturn、到達末尾)退出時解除分配。一個例外是VLA;它們的儲存在宣告執行時分配,而不是在塊進入時,並在宣告超出作用域時解除分配,而不是在塊退出時(C99起)。如果塊被遞迴進入,則每個遞迴級別都會執行新的分配。所有函式引數和非static塊作用域物件都具有此儲存期,以及在塊作用域中使用的複合字面量(C23前)
  • 靜態儲存期。儲存期是程式的整個執行過程,並且物件中儲存的值只初始化一次,在main函式之前。所有宣告為static的物件以及所有具有內部或外部連結但未宣告為_Thread_local(C23前)thread_local(C23起)(C11起)的物件都具有此儲存期。
  • 執行緒儲存期。儲存期是建立它的執行緒的整個執行過程,並且物件中儲存的值線上程啟動時初始化。每個執行緒都有自己的、獨立的物件。如果執行訪問此物件的表示式的執行緒不是執行其初始化的執行緒,則行為是實現定義的。所有宣告為_Thread_local(C23前)thread_local(C23起)的物件都具有此儲存期。
(C11 起)

[編輯] 連結

連結指的是識別符號(變數或函式)在其他作用域中被引用的能力。如果一個具有相同識別符號的變數或函式在多個作用域中宣告,但不能從所有作用域中被引用,那麼會生成該變數的多個例項。識別以下連結

  • 無連結。變數或函式只能從其所在的作用域(塊作用域)中引用。所有未宣告為extern的塊作用域變數,以及所有函式引數和所有非函式或變數的識別符號都具有此連結。
  • 內部連結。變數或函式可以從當前翻譯單元中的所有作用域中引用。所有宣告為staticconstexpr(C23起)的檔案作用域變數都具有此連結,以及所有宣告為static的檔案作用域函式(靜態函式宣告只允許在檔案作用域)。
  • 外部連結。變數或函式可以從整個程式中的任何其他翻譯單元中引用。所有未宣告為staticconstexpr(C23起)的檔案作用域變數都具有此連結,所有未宣告為static的檔案作用域函式宣告,所有塊作用域函式宣告,以及,如果之前沒有可見的內部連結宣告,所有宣告為extern的變數或函式都具有此連結。

如果同一識別符號在同一翻譯單元中同時出現內部連結和外部連結,則行為是未定義的。這在使用了暫定定義時可能發生。

[編輯] 連結和庫

具有外部連結的宣告通常在標頭檔案中提供,以便所有#include該檔案的翻譯單元都可以引用在其他地方定義的相同識別符號。

任何出現在標頭檔案中的具有內部連結的宣告都會在每個包含該檔案的翻譯單元中產生一個單獨且不同的物件。

庫介面,標頭檔案 "flib.h"

#ifndef FLIB_H
#define FLIB_H
void f(void);              // function declaration with external linkage
extern int state;          // variable declaration with external linkage
static const int size = 5; // definition of a read-only variable with internal linkage
enum { MAX = 10 };         // constant definition
inline int sum (int a, int b) { return a + b; } // inline function definition
#endif // FLIB_H

庫實現,原始檔 "flib.c"

#include "flib.h"
 
static void local_f(int s) {} // definition with internal linkage (only used in this file)
static int local_state;       // definition with internal linkage (only used in this file)
 
int state;                       // definition with external linkage (used by main.c)
void f(void) { local_f(state); } // definition with external linkage (used by main.c)

應用程式程式碼,原始檔 "main.c"

#include "flib.h"
 
int main(void)
{
    int x[MAX] = {size}; // uses the constant and the read-only variable
    state = 7;           // modifies state in flib.c
    f();                 // calls f() in flib.c
}

[編輯] 關鍵詞

auto, register, static, extern, _Thread_local thread_local

[編輯] 注意

關鍵字_Thread_local通常透過便利宏thread_local使用,該宏定義在標頭檔案<threads.h>中。

(直至 C23)

typedefconstexpr(C23起)說明符在C語言語法中形式上被列為儲存類說明符,但它們不指定儲存。

auto說明符也用於型別推斷。

(自 C23 起)

檔案作用域中宣告為const且不是extern的名稱在C中具有外部連結(作為所有檔案作用域宣告的預設值),但在C++中具有內部連結。

[編輯] 示例

#include <stdio.h>
#include <stdlib.h>
 
// static storage duration
int A;
 
int main(void)
{
    printf("&A = %p\n", (void*)&A);
 
    // automatic storage duration
    int A = 1;   // hides global A
    printf("&A = %p\n", (void*)&A);
 
    // allocated storage duration
    int* ptr_1 = malloc(sizeof(int));   // start allocated storage duration
    printf("address of int in allocated memory = %p\n", (void*)ptr_1);
    free(ptr_1);                        // stop allocated storage duration
}

可能的輸出

&A = 0x600ae4
&A = 0x7ffefb064f5c
address of int in allocated memory = 0x1f28c30

[編輯] 參考

  • C23 標準 (ISO/IEC 9899:2024)
  • 6.2.2 識別符號的連結 (p: 35-36)
  • 6.2.4 物件的儲存期 (p: 36-37)
  • 6.7.1 儲存類說明符 (p: 97-100)
  • C17 標準 (ISO/IEC 9899:2018)
  • 6.2.2 識別符號的連結 (p: 29-30)
  • 6.2.4 物件的儲存期 (p: 30)
  • 6.7.1 儲存類說明符 (p: 79)
  • C11 標準 (ISO/IEC 9899:2011)
  • 6.2.2 識別符號的連結 (p: 36-37)
  • 6.2.4 物件的儲存期 (p: 38-39)
  • 6.7.1 儲存類說明符 (p: 109-110)
  • C99 標準 (ISO/IEC 9899:1999)
  • 6.2.2 識別符號的連結 (p: 30-31)
  • 6.2.4 物件的儲存期 (p: 32)
  • 6.7.1 儲存類說明符 (p: 98-99)
  • C89/C90 標準 (ISO/IEC 9899:1990)
  • 3.1.2.2 識別符號的連結
  • 3.1.2.4 物件的儲存期
  • 3.5.1 儲存類說明符

[編輯] 另請參閱

C++ 文件,關於儲存類說明符