Namespaces
Variants

Storage-class specifiers

From cppreference.net

オブジェクトと関数の storage duration linkage を指定します:

  • auto - 自動ストレージ期間とリンケージなし
  • register - 自動ストレージ期間とリンケージなし;この変数のアドレスを取得できない
  • static - 静的ストレージ期間と内部リンケージ(ブロックスコープでない場合)
  • extern - 静的ストレージ期間と外部リンケージ(既に内部リンケージで宣言されていない場合)
  • _Thread_local (C23まで) thread_local (C23から) - スレッド記憶域期間
(C11から)

目次

説明

ストレージクラス指定子は 宣言 および 複合リテラル (C23以降) に現れます。最大で1つの指定子が使用可能です (ただし _Thread_local (C23以前) thread_local (C23以降) はリンケージを調整するために static または extern と組み合わせることが可能) (C11以降) 。ストレージクラス指定子は、それらが宣言する名前の2つの独立した特性: ストレージ期間 リンケージ を決定します。

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以降) スレッドストレージ期間 を示します。関数宣言では使用できません。オブジェクトの宣言で使用される場合、同じオブジェクトのすべての宣言に存在しなければなりません。ブロックスコープの宣言で使用される場合、 static または extern のいずれかと組み合わせてリンケージを決定する必要があります。
(C11以降)

ストレージクラス指定子が指定されない場合、デフォルトは以下の通りです:

extern すべての関数に対して
extern ファイルスコープのオブジェクトに対して
auto ブロックスコープのオブジェクトに対して

ストレージクラス指定子で宣言された任意の構造体または共用体について、そのストレージ期間(ただしリンケージは除く)は、それらのメンバに再帰的に適用されます。

ブロックスコープでの関数宣言は extern または何も指定しないことができます。ファイルスコープでの関数宣言は extern または static を使用できます。

関数パラメータには、 register 以外のストレージクラス指定子を使用できません。 static が配列型の関数パラメータで特別な意味を持つことに注意してください。

ストレージ期間

すべての object には storage duration と呼ばれる特性があり、これはobjectの lifetime を制限します。C言語には4種類のstorage durationがあります:

  • automatic ストレージ期間。オブジェクトが宣言された ブロック に入ったときにストレージが割り当てられ、何らかの方法で( goto return 、終端到達)ブロックを出たときに解放される。 例外は VLA であり、そのストレージはブロック進入時ではなく宣言が実行されたときに割り当てられ、ブロック終了時ではなく宣言がスコープ外に出たときに解放される (C99以降) 。ブロックが再帰的に進入された場合、各再帰レベルで新たな割り当てが行われる。全ての関数引数と非 static ブロックスコープオブジェクトはこのストレージ期間を持ち、 ブロックスコープで使用される 複合リテラル も同様 (C23以前)
  • static ストレージ期間。ストレージ期間はプログラムの実行全体にわたり、オブジェクトに格納される値は main関数 の前に一度だけ初期化される。 static で宣言された全てのオブジェクトと、内部リンケージまたは外部リンケージを持つ全てのオブジェクト _Thread_local (C23以前) thread_local (C23以降) で宣言されていないもの (C11以降) はこのストレージ期間を持つ。
  • thread ストレージ期間。このストレージ期間は、オブジェクトが作成されたスレッドの実行全体にわたり、オブジェクトに格納された値はスレッド開始時に初期化されます。各スレッドは独自の独立したオブジェクトを持ちます。このオブジェクトにアクセスする式を実行するスレッドが、その初期化を実行したスレッドでない場合、その動作は実装定義です。 _Thread_local (C23まで) thread_local (C23以降) と宣言されたすべてのオブジェクトはこのストレージ期間を持ちます。
(C11以降)
  • allocated ストレージ期間。ストレージは、 動的メモリ確保 関数を使用して要求に応じて割り当ておよび解放されます。

リンケージ

リンケージとは、識別子(変数または関数)が他のスコープから参照される能力を指します。同じ識別子を持つ変数または関数が複数のスコープで宣言されても、それらすべてから参照できない場合、変数の複数のインスタンスが生成されます。以下のリンケージが認識されます:

  • リンケージなし 。変数または関数は、それが存在するスコープ(ブロックスコープ)からのみ参照できます。 extern として宣言されていないすべてのブロックスコープ変数、およびすべての関数パラメータ、関数や変数ではないすべての識別子がこのリンケージを持ちます。
  • internal linkage 。変数または関数は、現在の翻訳単位内のすべてのスコープから参照できます。ファイルスコープの変数で static または constexpr (C23以降) として宣言されたものはすべてこのリンケージを持ち、ファイルスコープの関数で static として宣言されたもの(static関数宣言はファイルスコープでのみ許可されます)も同様です。
  • external linkage 。変数または関数はプログラム全体の他の翻訳単位から参照可能。ファイルスコープの変数で static が宣言されていないもの または constexpr が宣言されていないもの (C23以降) はすべてこのリンケージを持つ。 static が宣言されていないすべてのファイルスコープ関数宣言、すべてのブロックスコープ関数宣言、さらに extern で宣言されたすべての変数または関数は、その時点で内部リンケージを持つ先行宣言が可視でない限り、このリンケージを持つ。

同じ識別子が同じ翻訳単位内で内部リンケージと外部リンケージの両方で現れる場合、動作は未定義です。これは 暫定的な定義 が使用されている場合に発生する可能性があります。

リンケージとライブラリ

外部リンケージを持つ宣言は、通常ヘッダーファイルで利用可能にされ、そのファイルを #include するすべての翻訳単位が、他の場所で定義されている同じ識別子を参照できるようにします。

内部リンケージを持つ宣言がヘッダーファイルに存在する場合、そのファイルをインクルードする各翻訳単位で個別のオブジェクトが生成されます。

ライブラリインターフェース、ヘッダーファイル "flib.h":

#ifndef FLIB_H
#define FLIB_H
void f(void);              // 外部リンケージを持つ関数宣言
extern int state;          // 外部リンケージを持つ変数宣言
static const int size = 5; // 内部リンケージを持つ読み取り専用変数の定義
enum { MAX = 10 };         // 定数定義
inline int sum (int a, int b) { return a + b; } // インライン関数定義
#endif // FLIB_H

ライブラリ実装、ソースファイル "flib.c":

#include "flib.h"
static void local_f(int s) {} // 内部リンケージを持つ定義(このファイル内でのみ使用)
static int local_state;       // 内部リンケージを持つ定義(このファイル内でのみ使用)
int state;                       // 外部リンケージを持つ定義(main.cで使用)
void f(void) { local_f(state); } // 外部リンケージを持つ定義(main.cで使用)

アプリケーションコード、ソースファイル「main.c」:

#include "flib.h"
int main(void)
{
    int x[MAX] = {size}; // 定数と読み取り専用変数を使用
    state = 7;           // flib.c内のstateを変更
    f();                 // flib.c内のf()を呼び出し
}

キーワード

auto , register , static , extern , _Thread_local thread_local

注記

キーワード _Thread_local は通常、ヘッダー <threads.h> で定義される便利マクロ thread_local を通じて使用されます。

(C23まで)

C言語の文法では、 typedef および constexpr (C23以降) 指定子は形式的に記憶クラス指定子として分類されていますが、実際には記憶域を指定するものではありません。

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++ ドキュメント for Storage class specifiers
翻訳の説明: - 「C++ documentation」→「C++ ドキュメント」に翻訳 - 「for」はそのまま保持(文脈上、英語のままが適切) - 「Storage class specifiers」はC++専門用語のため翻訳せず保持 - HTMLタグ、属性、構造は完全に保持 - タイトル属性内のテキストも翻訳対象外として保持