C言語にクラスはありませんが、構造体と共用体ならあります。また、C++と同様、列挙体も使うことができます。
タグ名だけで型名にならない
C++ではクラスや列挙体のタグ名だけで型名になりましたが、C言語では明示的にstruct, union, またはenumを付けなければなりません。それが嫌ならtypedef名を定義する必要があります。
0 1 2 3 4 5 |
struct A { int a; }; A x; /* エラー */ struct A x; /* OK */ |
クラス有効範囲のようなものはない
C++では、クラスの中でクラスを定義した場合、入れ子になったクラスは外側のクラスのクラス有効範囲に属します。しかし、C言語ではクラス有効範囲という概念がないため、このようなことはありません。
0 1 2 3 4 5 6 7 8 9 10 |
struct A { struct B { int value; } b; } a; struct B x; /* OK */ |
構造体や共用体の中で型定義はできない
C言語にはクラス有効範囲がありませんので、構造体や共用体の中で型定義を行うことができません。
0 1 2 3 4 5 6 7 8 9 |
struct A { typedef int int_t; /* エラー */ struct B { int b; }; /* エラー */ enum { c, d }; /* エラー */ int a; }; |
集成体
C言語では、「集成体」という用語は構造体と配列の総称です。共用体は集成体ではありません。
構造体のメモリ配置
構造体型のオブジェクトへのポインタは、そのオブジェクトの最初のメンバへのポインタと同じアドレスをさします。また、構造体のメンバは上から順に、メモリの下位→上位の順に配置されます。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <assert.h> struct A { int a; double b; }; int main(void) { struct A x; assert(&x == (struct A*)&x.a); /* OK */ return 0; } |
構造体や共用体のメンバは必須
C言語では、メンバのない構造体や共用体を定義することはできません。
ビットフィールド
C言語(C89)では、ビットフィールドの型として使えるのは、int, signed int, およびunsigned intだけです。signedもunsignedも付かない単なるintの場合、符号付きか符号無しかは、C++と同様、処理系定義です。
無名共用体は使えない
C言語では、無名共用体をメンバ名だけでアクセスすることはできません。
0 1 2 3 4 5 6 7 8 9 10 11 |
int main(void) { union { int a; char b[10]; }; a = 123; /* エラー */ return 0; } |
列挙定数はint型
C言語は、列挙定数は常にint型になります。列挙体型は処理系定義の汎整数型になります。
式中での型定義
C言語では、式や関数の仮引数並びで型定義を行うことができます。具体的には、次のようなことができます。
0 1 2 |
a = ((struct { int a; double b; }*)ptr)->b; |