Namespaces
Variants

Type

From cppreference.net

(関連項目: arithmetic types で組み込み型の詳細と、 the list of type-related utilities Cライブラリが提供する型関連ユーティリティの一覧も参照してください。)

Objects functions 、および expressions type と呼ばれる特性を持ち、これはオブジェクトに格納された、または式によって評価されたバイナリ値の解釈を決定します。

目次

型の分類

C言語の型システムは以下の型で構成されます:

  • the type void
  • 基本型
  • char
  • 符号付き整数型
  • 標準: signed char , short , int , long , long long (C99以降)
  • ビット精度: _BitInt ( N ) ここでNは、符号ビットを含む型を表現するために使用されるビット数を指定する整数定数式です。Nの各値は異なる型を指定します。
(C23以降)
  • 拡張: 実装定義、例: __int128
(C99以降)
  • 符号なし整数型
  • 標準: _Bool , (since C99) unsigned char , unsigned short , unsigned int , unsigned long , unsigned long long (since C99)
  • ビット精度: unsigned _BitInt ( N ) ここで N は型を表現するために使用されるビット数を指定する整数定数式です。 N の各値は異なる型を指定します。このカテゴリには型 unsigned _BitInt ( 1 ) が含まれますが、これは対応するビット精度の符号付き整数型を持ちません。
(C23以降)
  • 拡張: 実装定義、例: __uint128
(C99以降)
  • 浮動小数点型
  • 実浮動小数点型: float , double , long double
  • 10進実浮動小数点型: _Decimal32 , _Decimal64 , _Decimal128
(C23以降)
  • 複素数型: float _Complex , double _Complex , long double _Complex
  • 虚数型: float _Imaginary , double _Imaginary , long double _Imaginary
(C99以降)
  • derived types
(C11以降)

上記の各型に対して、その型の修飾版が複数存在する可能性があります。これは、 const volatile 、および restrict 修飾子(修飾子の意味論で許可される場合)のうち、1つ、2つ、またはすべての3つの組み合わせに対応します。

型グループ

  • オブジェクト型 : 関数型ではないすべての型
  • 文字型 : char , signed char , unsigned char
  • 整数型 : char , 符号付き整数型, 符号なし整数型, 列挙型
  • 実数型 : 整数型と実浮動小数点型
  • 算術型 : 整数型と浮動小数点型
  • スカラー型 : 算術型, ポインタ型 , および nullptr_t (C23以降)
  • 集成体型 : 配列型と構造体型
  • 派生宣言子型 : 配列型, 関数型, ポインタ型

完全なオブジェクト型を、そのオブジェクト表現におけるバイト数が型 size_t (すなわち sizeof 演算子の結果型)で表現できないように構築すること (実行時にそのようなVLA型を形成する場合を含む) (C99以降) は未定義動作である。

互換性のある型

Cプログラムにおいて、同じオブジェクトまたは関数を参照する宣言は、 異なる翻訳単位 で同じ型を使用する必要はありません。それらは十分に類似した型、正式には 互換性のある型 を使用するだけで十分です。同じことが関数呼び出しとlvalueアクセスにも適用されます。引数の型はパラメータの型と 互換性 がなければならず、lvalue式の型はアクセスされるオブジェクトの型と 互換性 がなければなりません。

T U は、以下の場合に互換性があります:

  • それらが同じ型である(同じ名前または typedef によって導入されたエイリアス)
  • それらが互換性のある非修飾型の同一の cvr 修飾版である
  • それらがポインタ型であり、互換性のある型を指している
  • それらが配列型であり、かつ
  • それらの要素型が互換性があり、かつ
  • 両方が定数サイズを持つ場合、そのサイズが同じであること。注記: 未知の境界を持つ配列は、互換性のある要素型を持つ任意の配列と互換性があります。 VLAは互換性のある要素型を持つ任意の配列と互換性があります。 (C99以降)
  • それらは両方とも構造体/共用体/列挙型であり、
  • (C99) 一方がタグ付きで宣言されている場合、他方も同じタグで宣言されなければならない。
  • 両方が完全型である場合、それらのメンバーは数が正確に一致し、互換性のある型で宣言され、一致する名前を持たなければならない。
  • さらに、それらが列挙型である場合、対応するメンバーは同じ値を持たなければならない。
  • さらに、それらが構造体または共用体である場合、
  • 対応するメンバーは同じ順序で宣言されなければならない(構造体のみ)
  • 対応する bit-fields は同じ幅を持たなければならない。
  • oneは列挙型であり、もう一方はその列挙型の基盤となる型です
  • それらは関数型であり、かつ
  • それらの戻り値の型は互換性がある
  • 両方ともパラメータリストを使用しており、パラメータの数(省略記号の使用を含む)は同じであり、配列からポインタへの変換および関数からポインタへの型調整を適用し、トップレベルの修飾子を取り除いた後の対応するパラメータの型が互換性を持つ
  • 一方は旧形式(パラメータなし)の定義であり、もう一方はパラメータリストを持つ。パラメータリストは省略記号を使用せず、各パラメータは(関数パラメータ型調整後)対応する旧形式パラメータとデフォルト引数プロモーション後の互換性がある
  • 一方は旧形式(パラメータなし)の宣言であり、もう一方はパラメータリストを持つ。パラメータリストは省略記号を使用せず、すべてのパラメータ(関数パラメータ型調整後)はデフォルト引数プロモーションの影響を受けない
(C23まで)

char signed char と互換性がなく、 unsigned char とも互換性がありません。

2つの宣言が同じオブジェクトまたは関数を参照し、互換性のある型を使用しない場合、プログラムの動作は未定義です。

// 翻訳単位1
struct S { int a; };
extern struct S *x; // TU2のxと互換性があるが、TU3のxとは互換性がない
// 翻訳単位2
struct S;
extern struct S *x; // 両方のxと互換性がある
// 翻訳単位3
struct S { float a; };
extern struct S *x; // TU2のxと互換性があるが、TU1のxとは互換性がない
// 動作は未定義
// 翻訳単位 1
#include <stdio.h>
struct s { int i; }; // TU3のsと互換性あり、TU2のsとは非互換
extern struct s x = {0}; // TU3のxと互換性あり
extern void f(void); // TU2のfと互換性あり
int main()
{
    f();
    return x.i;
}
// 翻訳単位 2
struct s { float f; }; // TU4のsと互換性あり、TU1のsとは非互換
extern struct s y = {3.14}; // TU4のyと互換性あり
void f() // TU1のfと互換性あり
{
    return;
}
// 翻訳単位 3
struct s { int i; }; // TU1のsと互換性あり、TU2のsとは非互換
extern struct s x; // TU1のxと互換性あり
// 翻訳単位 4
struct s { float f; }; // TU2のsと互換性あり、TU1のsとは非互換
extern struct s y; // TU2のyと互換性あり
// 動作は明確に定義されている: オブジェクトと関数の複数宣言のみが互換性のある型を持つ必要があり、型自体は必要ない

注記: C++には互換性のある型という概念は存在しません。異なる翻訳単位で互換性はあるが同一ではない2つの型を宣言するCプログラムは、有効なC++プログラムではありません。

複合型

複合型は互換性のある2つの型から構成される型であり、以下の条件を満たす両方の型と互換性を持つ型です:

  • 両方の型が配列型の場合、以下の規則が適用されます:
  • 一方の型が既知の定数サイズの配列である場合、合成型はそのサイズの配列となります。
  • それ以外の場合、一方の型が評価されない式でサイズが指定されるVLAであり、両方の型の合成型を必要とするプログラムは未定義動作となります。
  • それ以外の場合、一方の型がサイズ指定されたVLAである場合、合成型はそのサイズのVLAとなります。
  • それ以外の場合、一方の型がサイズ未指定のVLAである場合、合成型はサイズ未指定のVLAとなります。
(C99以降)
  • それ以外の場合、両方の型は未知のサイズの配列であり、合成型は未知のサイズの配列となります。
合成型の要素型は、二つの要素型の合成型です。
  • 片方の型のみがパラメータ型リスト(関数プロトタイプ)を持つ関数型である場合、合成型はそのパラメータ型リストを持つ関数プロトタイプとなります。
(C23まで)
  • 両方の型がパラメータ型リストを持つ関数型の場合、合成パラメータ型リスト内の各パラメータの型は、対応するパラメータの合成型となります。

これらの規則は、2つの型が派生する元の型に対して再帰的に適用されます。

// 以下の2つのファイルスコープ宣言が与えられた場合:
int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]); // C23: エラー: 'f' の型が競合しています
// 関数の合成結果の型は以下の通り:
int f(int (*)(char *), double (*)[3]);

内部リンケージまたは外部リンケージを持つ識別子が、その識別子の先行宣言が見えるスコープで宣言された場合、先行宣言が内部リンケージまたは外部リンケージを指定しているときは、後の宣言における識別子の型は複合型となります。

不完全型

不完全型は、その型のオブジェクトのサイズを決定するのに十分な情報が欠けているオブジェクト型です。不完全型は翻訳単位内のある時点で完全型に完了される可能性があります。

以下の型は不完全です:

  • the type void . この型は完全型にすることができません。
  • サイズが不明な配列型。後続の宣言でサイズを指定することで完全型にすることができます。
extern char a[]; // aの型は不完全(これは通常ヘッダーファイルに記述される)
char a[10];      // aの型は完全となった(これは通常ソースファイルに記述される)
  • 内容が不明な構造体または共用体の型。同じスコープ内で後からその内容を定義する同じ構造体または共用体の宣言によって完成させることができます。
struct node
{
    struct node* next; // この時点では struct node は不完全型です
}; // この時点で struct node は完全型になります

型名

型は、 宣言 以外の文脈で名前を付けられる必要がある場合があります。このような状況では、 型名 が使用されます。これは文法的に、 type-specifiers type-qualifiers のリストの後に declarator が続く形式( declarations を参照)と全く同じですが、識別子が省略される点が異なります:

int n; // intの宣言
sizeof(int); // 型名の使用
int *a[3]; // intへの3つのポインタの配列の宣言
sizeof(int *[3]); // 型名の使用
int (*p)[3]; // 3つのintの配列へのポインタの宣言
sizeof(int (*)[3]); // 型名の使用
int (*a)[*] // VLAへのポインタの宣言(関数パラメータ内)
sizeof(int (*)[*]) // 型名の使用(関数パラメータ内)
int *f(void); // 関数の宣言
sizeof(int *(void)); // 型名の使用
int (*p)(void); // 関数へのポインタの宣言
sizeof(int (*)(void)); // 型名の使用
int (*const a[])(unsigned int, ...) = {0}; // 関数へのポインタの配列
sizeof(int (*const [])(unsigned int, ...)); // 型名の使用

識別子を囲む冗長な括弧は型名において意味を持ち、「パラメータ指定なしの関数」を表すことを除いて:

int (n); // int型のnを宣言
sizeof(int ()); // 「intを返す関数」型を使用

型名は以下の状況で使用されます:

(C99以降)
(C11以降)


型名は新しい型を導入することがあります:

void* p = (void*)(struct X { int i; } *)0;
// キャスト式で使用された型名 "struct X {int i;}*" は
// 新しい型 "struct X" を導入する
struct X x = {1}; // struct X は現在スコープ内にある

参考文献

  • C23規格 (ISO/IEC 9899:2024):
  • 6.2.5 型 (p: TBD)
  • 6.2.6 型の表現 (p: TBD)
  • 6.2.7 互換性のある型と合成型 (p: TBD)
  • C17規格 (ISO/IEC 9899:2018):
  • 6.2.5 型 (p: 31-33)
  • 6.2.6 型の表現 (p: 31-35)
  • 6.2.7 互換性のある型と合成型 (p: 35-36)
  • C11規格 (ISO/IEC 9899:2011):
  • 6.2.5 型 (p: 39-43)
  • 6.2.6 型の表現 (p: 44-46)
  • 6.2.7 互換性のある型と合成型 (p: 47-48)
  • C99規格 (ISO/IEC 9899:1999):
  • 6.2.5 型 (p: 33-37)
  • 6.2.6 型の表現 (p: 37-40)
  • 6.2.7 互換性のある型と合成型 (p: 40-41)
  • C89/C90標準 (ISO/IEC 9899:1990):
  • 3.1.2.5 型
  • 3.1.2.6 互換性のある型と合成型

関連項目