型
(ほとんどの組み込み型の詳細は算術型を参照してください。Cライブラリによって提供される型関連のユーティリティの一覧も参照してください)
オブジェクト、関数、式は型と呼ばれる特性を持ち、その式によって評価されるオブジェクトが保持するバイナリ値の解釈を決定します。
目次 |
[編集] 型の分類
Cの型システムは以下の型から構成されます。
- void型
- 基本型
- char型
- 符号付き整数型
- 標準: signed char, short, int, long, long long (C99以上)
- 拡張: 処理系定義 (例: __int128)
- 符号なし整数型
- 標準: _Bool (C99以上), unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long (C99以上)
- 拡張: 処理系定義 (例: __uint128)
- 浮動小数点型
- 実数: float, double, long double
- 複素数: float _Complex, double _Complex, long double _Complex
- 虚数: float _Imaginary, double _Imaginary, long double _Imaginary
- 派生型
上記に挙げたすべての型に対して、 const, volatile, restrict 修飾子を1つ、2つまたは3つの組み合わせに対応する修飾されたバージョンの型が存在する場合があります (その修飾子の意味論が許す限りにおいて)。
[編集] 型のグループ
- オブジェクト型: 関数型でないすべての型
- 文字型: char, signed char, unsigned char
- 整数型: char, 符号付き整数型、符号なし整数型、列挙型
- 実数型: 整数型および実数浮動小数点型
- 算術型: 整数型および浮動小数点型
- スカラー型: 算術型およびポインタ型
- 集成体型: 配列型および構造体型
- 派生宣言子型: 配列型、関数型、ポインタ型
[編集] 互換な型
Cのプログラムでは、異なる翻訳単位の同じオブジェクトや関数を参照する宣言は、同じ型を使う必要はありません。 十分に似た型、正式には互換な型と呼ばれるものを使う必要があるだけです。 同じことが関数呼び出しや左辺値へのアクセスにも適用されます。 実引数の型は仮引数の型と互換でなければならず、左辺値の式はアクセス対象のオブジェクトの型と互換でなければなりません。
型 T
と型 U
は以下の場合に互換です。
- 両者が同じ型 (同じ名前または typedef によって導入された別名) である
- 両者が互換な無修飾型に対して同じように cvr-修飾された型である
- 両者がポインタ型であり、互換な型を指す
- 両者が配列であり、かつ
- その要素型が互換であり、かつ
- 両者が定数のサイズを持つ場合、そのサイズが同じである。 ノート: サイズの不明な配列は要素型が互換な任意の配列と互換です。 VLAは要素型が互換な任意の配列と互換です。 (C99以上)
- 両者が構造体、共用体、列挙型であり、かつ
- (C99)一方がタグ付きで宣言されている場合、他方も同じタグを付けて宣言されなければなりません。
- 両者が完全型である場合、それらの対応するメンバは数が一致し、互換な型で宣言され、一致する名前を持たなければなりません。
- さらに、両者が列挙型である場合、対応するメンバは同じ値を持たなければなりません。
- さらに、両者が構造体または共用体の場合、
- 対応するメンバは同じ順序せ宣言されなければなりません (構造体のみ)
- 対応するビットフィールドは同じ幅を持たねばなりません
- 一方が列挙型で他方がその列挙の基底型である
- 両者が関数型であり、かつ
- 両者の戻り値の型が互換である
- 両者が引数リストを持ち、引数の数 (省略記号の使用も含みます) が同じであり、対応する引数が互換な型である
- 一方が旧形式 (引数なし) で定義され、他方が引数リストを持ち、引数リストに省略記号を含まず、各引数が (関数引数型の調整後に) 対応する旧形式の引数のデフォルトの引数昇格後の型と互換である
- 一方が旧形式 (引数なし) で宣言され、他方が引数リストを持ち、引数リストに省略記号を含まず、(関数引数型の調整後の) すべての引数がデフォルトの引数昇格の影響を受けない
char 型は signed char と互換ではなく、 unsigned char とも互換ではありません。
2つの宣言が同じオブジェクトまたは関数を参照していて、互換な型を使用していない場合、そのプログラムの動作は未定義です。
// Translation Unit 1 struct S {int a;}; extern struct S *x; // compatible with TU2's x, but not with TU3's x // Translation Unit 2 struct S; extern struct S *x; // compatible with both x's // Translation Unit 3 struct S {float a;}; extern struct S *x; // compatible with TU2's x, but not with TU1's x // the behavior is undefined
// Translation Unit 1 #include <stdio.h> struct s {int i;}; // compatible with TU3's s, but not TU2's extern struct s x = {0}; // compatible with TU3's x extern void f(void); // compatible with TU2's f int main() { f(); return x.i; } // Translation Unit 2 struct s {float f;}; // compatible with TU4's s, but not TU1's s extern struct s y = {3.14}; // compatible with TU4's y void f() // compatible with TU1's f { return; } // Translation Unit 3 struct s {int i;}; // compatible with TU1's s, but not TU2's s extern struct s x; // compatible with TU1's x // Translation Unit 4 struct s {float f;}; // compatible with TU2's s, but not TU1's s extern struct s y; // compatible iwth TU2's y // the behavior is well-defined: only multiple declarations // of objects and functions must have compatible types, not the types themselves
ノート: C++には互換な型という概念はありません。 異なる翻訳単位で互換だけれども同一でない2つの型を宣言するCのプログラムは、有効なC++のプログラムではありません。
[編集] 合成型
1つの合成型を2つの互換な型から構築できます。 両者の型が互換であり、以下の条件を満たす場合、それは互換な型です。
- 両者の型が配列型の場合、以下のルールが適用されます。
- 一方の型が既知の定数サイズの配列である場合、合成型はそのサイズの配列です
|
(C99以上) |
- そうでなければ、両者の型はサイズの不明な配列であり、合成型はサイズの不明な配列です
- 合成型の要素型は2つの要素型の合成型です
- 一方の型が引数型リスト付きの関数型 (関数プロトタイプ) である場合、合成型はその引数型リスト付きの関数プロトタイプです
- 両者の型が引数型リスト付きの関数型である場合、合成型の引数型リストのそれぞれの引数の型は対応する引数の合成型です。
これらのルールは2つの型の派生元となった型に再帰的に適用されます。
// Given the following two file scope declarations: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // The resulting composite type for the function is: int f(int (*)(char *), double (*)[3]);
内部または外部リンケージを持つ識別子が、以前に宣言されたその識別子が可視であるスコープで宣言された場合、その以前の宣言が内部または外部リンケージを指定していれば、後に宣言された識別子の型は合成型になります。
[編集] 不完全型
不完全型はその型のオブジェクトのサイズを決定するための十分な情報が欠けているオブジェクト型です。 不完全型は翻訳単位のどこかの時点で完全型になる場合があります。
以下の型は不完全型です。
- void 型。 この型は完全型になることはできません。
- サイズの不明な配列型。 後の宣言でサイズが指定されれば完全型になります。
extern char a[]; // the type of a is incomplete (this typically appears in a header) char a[10]; // the type of a is now complete (this typically appears in a source file)
- 内容の不明な構造体型または共用隊型。 同じスコープで後に同じ構造体型または共用体型の内容を定義する宣言がなされれば完全型になります。
struct node { struct node *next; // struct node is incomplete at this point }; // struct node is complete at this point
[編集] 型名
型は宣言されたものと異なる分脈で名付けなければならない場合があります。 こういった状況では、型名は、その型のオブジェクトや関数を宣言するときに’’型指定子、型修飾子、宣言子 (宣言 を参照してください) のリストを使うのと文法的に全く同じように、ただし識別子は除いて、使われます。
int n; // declaration of an int sizeof(int); // use of type name int *a[3]; // declaration of an array of 3 pointers to int sizeof(int *[3]); // use of type name int (*p)[3]; // declaration of a pointer to array of 3 int sizeof(int (*)[3]); // use of type name int (*a)[*] // declaration of pointer to VLA (in a function parameter) sizeof(int (*)[*]) // use of type name (in a function parameter) int *f(void); // declaration of function sizeof(int *(void)); // use of type name int (*p)(void); // declaration of pointer to function sizeof(int (*)(void)); // use of type name int (*const a[])(unsigned int, ...) = {0}; // array of pointers to functions sizeof(int (*const [])(unsigned int, ...)); // use of type name
ただし、識別子のまわりの冗長な括弧は、型名においては意味を持ち、「引数仕様を持たない関数」を表します。
int (n); // declares n of type int sizeof(int ()); // uses type "function returning int"
型名は以下の状況で使われます。
(C99以上) | |
(C11以上) |
型名は新しい型を導入する場合があります。
void* p = (void*)(struct X {int i;} *)0; // type name "struct X {int i;}*" used in the cast expression // introduces the new type "struct X" struct X x = {1}; // struct X is now in scope
[編集] 参考文献
- C11 standard (ISO/IEC 9899:2011):
- 6.2.5 Types (p: 39-43)
- 6.2.6 Representations of types (p: 44-46)
- 6.2.7 Compatible type and composite type (p: 47-48)