記憶クラス

記憶クラス (storage class) は、変数や関数を配置する場所に影響します。各変数または関数につき、次の記憶クラスを最大 1 つ指定できます。

記憶クラス説明
auto 自動変数
extern 外部参照
static 静的変数、またはファイル内関数
register レジスタ変数
typedef 型定義

auto

局所変数の既定の記憶クラスです。局所変数には暗黙で指定され、局所変数以外には指定できないため、あまり使用されません。
void func() {
  auto int r = 3; // 単に「int r = 3;」でも同じ
  return 3;
}

extern

広域変数または関数が別のファイルで定義されていることを示します。
extern int gvar; // 外部変数宣言
extern int func( char* ); // 外部関数宣言
int func( char* ); // 上と同じ

関数宣言では extern を省略しても同じ結果になります。

実際にその変数または関数が他ファイルで定義されていないと、リンク時にエラーになります。また、実際の定義と extern 宣言の型が一致していないと、不測の結果になります。

static

このキーワードには次の 2 つの役割があります。

static int lvar; // ファイル内でのみ有効な変数
static int func( char* ); // ファイル内でのみ有効な関数
int counter() { // 呼び出された回数を返す関数
  static int c = 0; // これを static にしないと毎回 0 にリセットされてしまう
  return ++c;
}

register

int と同じサイズの局所変数 (int、short、unsigned int、near ポインタなど) に register を指定すると、その変数は、スタックではなくレジスタ si または di に置かれます。char、long、float、double、far ポインタ、配列などをレジスタ変数に割り当てることはできません。レジスタ変数は、同時に 2 つまで使用できます。

これにより、変数へのアクセスが高速になります。頻繁に使用する変数、特にポインタに指定すると効果があります。

-o または -or を指定すると、register を記述しなくても、コンパイラの判断で自動的にレジスタ変数が使用されます。ただし、この場合でも明示的な register 指定が優先されます。

typedef

typedef は型を定義する特別なキーワードです。定義した型名は、通常の型名 (int, char* など) と同じように使用できます。

typedef unsigned int uint;
uint x; // unsigned int x と同じ

typedef で定義した型名を使用して、さらに別の名前を定義することもできます。

typedef unsigned int uint;
typedef uint* puint;
puint p; // unsigned int* p と同じ

定義内容が矛盾しない限り、同じ名前を typedef で複数回定義できます。[LC]

typedef unsigned int uint;
typedef unsigned int uint; // 可
typedef unsigned long uint; // エラー

ただし、次の定義はエラーになります。

typedef unsigned uint;
typedef unsigned uint;

これは、unsigned だけでは型が完結しないためです。typedef 定義名を再定義する場合は、unsigned int などの完全な型名を使用してください。

_noreg [LC]

このクラスを指定された局所変数は、レジスタに割り付けられず、必ずスタック上に領域が確保されます。

inline [LC]

関数に対して指定する記憶クラスです。インライン関数を定義します。
inline int max( int a, int b ) { return a >= b ? a : b; }

インライン関数を呼び出すと、関数呼び出しコードが生成される代わりに、呼び出しの位置に関数のコードが埋め込まれます。このため、コード サイズは増大する可能性がありますが、関数呼び出しが高速になります。

一般に、高速に実行したい小さな関数をインライン関数に指定します。呼び出す前に同一のソース ファイルまたはヘッダー ファイルで定義されている必要があります。