名前空間
変種
操作

記憶域クラス指定子

提供: cppreference.com
< c‎ | language

オブジェクトおよび関数の記憶域期間およびリンケージを指定します。

  • auto ー 自動記憶域期間、リンケージなし。
  • register ー 自動記憶域期間、リンケージなし。 この変数のアドレスを取ることはできません。
  • static ー 静的記憶域期間、内部リンケージ (ブロックスコープの場合を除く)。
  • extern ー 静的記憶域期間、外部リンケージ (すでに内部リンケージとして宣言されている場合を除く)。
  • _Thread_local ー スレッド記憶域期間。
(C11以上)

目次

[編集] 説明

記憶域クラス指定子は宣言内に現れます。 多くとも1つの指定子を指定することができます。 ただし _Thread_local はリンケージを調節するために static または extern と組み合わせることができます。 (C11以上) 記憶域クラス指定子はその宣言対象の名前に対する独立した2つの性質、記憶域期間リンケージを決定します。

1) auto 指定子はブロックスコープで宣言されるオブジェクト (関数の仮引数リストを除く) に対してのみ使用できます。 これは自動記憶域期間とリンケージなしを表します (これはこれらの種類の宣言に対するデフォルトです)。
2) register 指定子はブロックスコープで宣言されるオブジェクト (関数の仮引数リストを含む) に対してのみ使用できます。 これは自動記憶域期間とリンケージなしを表します (これはこれらの種類の宣言に対するデフォルトです) が、さらに、可能であればこの変数の値を CPU のレジスタに格納するよう最適化のヒントを与えます。 この最適化が行われるか否かに関わらず、 register 宣言された変数はアドレス取得演算子の引数として使用することができません。 また、 alignas も使用できません。 (C11以上) さらに、 register 配列はポインタに変換できません。
3) static 指定子は静的記憶域期間 (_Thread_local と組み合わせた場合を除く) (C11以上)と内部リンケージ (ブロックスコープの場合を除く) を指定します。 ファイルスコープの関数およびファイルスコープとブロックスコープ両方の変数で使用することができますが、関数の仮引数リストでは使用できません。
4) extern 指定子は静的記憶域期間 (_Thread_local と組み合わせた場合を除く) (C11以上)と外部リンケージを指定します。 ファイルスコープとブロックスコープ両方の関数およびオブジェクト (関数の仮引数リストを除く) で使用できます。 すでに内部リンケージで宣言された識別子の再宣言で extern が現れた場合は、そのリンケージは内部のままです。 そうでなければ (前の宣言が外部またはリンケージなしであるか、スコープ内にない場合)、リンケージは外部です。
5) _Thread_localスレッド記憶域期間を表します。 関数の宣言で使用することはできません。 オブジェクトの宣言で使用される場合は、その同じオブジェクトのすべての宣言で使用されなければなりません。 ブロックスコープの宣言で使用される場合は、リンケージを決定するために static または extern のいずれかと組み合わせなければなりません。
(C11以上)

記憶域クラス指定子が提供されない場合は、デフォルトは以下の通りです。

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

記憶域クラス指定子付きで宣言されたあらゆる構造体または共用体について、その記憶域期間がそのメンバに再帰的に適用されます (しかしリンケージは適用されません)。

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

関数の仮引数は、 register 以外、何の記憶域クラス指定子も使用することができません。 関数の配列型の仮引数では static に特別な意味があることに注意してください。

[編集] 記憶域期間

すべてのオブジェクト記憶域期間と呼ばれる性質を持ちます。 これはオブジェクトの生存期間を制限します。 C では4種類の記憶域期間があります。

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

[編集] リンケージ

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

  • リンケージなし。 識別子はその存在するスコープからのみ参照できます。 すべての関数の仮引数およびすべての extern でないブロックスコープの変数 (static 宣言されたものを含む) はこのリンケージを持ちます。
  • 内部リンケージ。 識別子は現在の翻訳単位内のすべてのスコープから参照できます。 すべての static なファイルスコープの識別子 (関数と変数の両方) はこのリンケージを持ちます。
  • 外部リンケージ。 プログラム全体のあらゆる翻訳単位から参照できます。 すべての static でない関数、すべての extern 変数 (すでに static 宣言されていたものを除く)、およびすべてのファイルスコープの static でない変数はこのリンケージを持ちます。

同じ翻訳単位に内部と外部両方のリンケージで同じ識別子が現れた場合、動作は未定義です。 これは仮定義が使用されたときに起き得ます。

[編集] リンケージとライブラリ

外部リンケージ付きの宣言は一般的にはヘッダファイルで利用可能にされます。 そのファイルを #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 内の状態を変更します
    f();                 // flib.c 内の f() を呼びます
}

[編集] キーワード

auto, register, static, extern, _Thread_local

[編集] ノート

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

typedef 指定子は、 C 言語の文法では形式的には記憶域クラス指定子として掲載されていますが、型名を宣言するために使用され、記憶域は指定しません。

const であり extern でないファイルスコープの名前は、 C では外部リンケージを持ちます (すべてのファイルスコープの宣言のデフォルトと同様) が、 C++ では内部リンケージを持ちます。

[編集]

#include <stdio.h>
#include <stdlib.h>
 
/* 静的記憶域期間 */
int A;
 
int main(void)
{
    printf("&A = %p\n", (void*)&A);
 
    /* 自動記憶域期間 */
    int A = 1;   // グローバルの A を隠蔽します。
    printf("&A = %p\n", (void*)&A);
 
    /* 自動記憶域期間 */
    int *ptr_1 = malloc(sizeof(int));   /* 確保された記憶域期間を開始します。 */
    printf("address of int in allocated memory = %p\n", (void*)ptr_1);
    free(ptr_1);                        /* 確保された記憶域期間を終了します。 */
 
}

出力例:

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

[編集] 参考文献

  • C11 standard (ISO/IEC 9899:2011):
  • 6.2.2 Linkages of identifiers (p: 36-37)
  • 6.2.4 Storage durations of objects (p: 38-39)
  • 6.7.1 Storage-class specifiers (p: 109-110)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.2.2 Linkages of identifiers (p: 30-31)
  • 6.2.4 Storage durations of objects (p: 32)
  • 6.7.1 Storage-class specifiers (p: 98-99)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 3.1.2.2 Linkages of identifiers
  • 3.1.2.4 Storage durations of objects
  • 3.5.1 Storage-class specifiers

[編集] 関連項目

記憶域クラス指定子C++リファレンス