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

