構造体
配列は、同一型のデータの集まりを扱うデータ型でした。
詳しくは、こちらに配列を書いています。
一方、異なる型のデータの集まりを作りたい場合があるかと思います。
その場合は、構造体というものを使います。
構造体は、同一の型も含め、異なる型、配列、ポインタなど、作りたいデータの集まりを自由に構成することができます。
構造体の書き方
構造体は、次のように書きます。
定義した構造体の実体の宣言は、
struct 構造体タグ名 構造体名;
のように記述し、構造体の各メンバーへのアクセスは、
構造体名.メンバー名;
というように、構造体名とメンバー名をドット演算子(ピリオド)でつなぎます。
struct position
{
int x;
int y;
int z;
};
main()
{
struct position pst;
pst.x = 1;
pst.y = 2;
pst.z = 3;
}
下の例は、バッファ内のデータ位置をnumで管理する構造体例です。
このように構造体では、配列も内部に組み込むことができます。
#define D_BUF_SIZE 100
struct buf{
unsigned short num;
unsigned char buffer[D_BUF_SIZE];
};
struct buf stbuf;
typedef
新しい自作のデータ型を作ることができます。自作データ型を作成するときに使うのがtypedef宣言です。
typedef 型 自作の型名;
のような書式で宣言します。
例えば、
typedef char B;
typedef short W;
typedef long DW;
main()
{
B dat;
dat = 1;
のようにchar型、short型、long型をそれぞれB,W,DWのような名前の型として定義できます。これにより、B型のdatという変数を宣言することができます。この変数datは、char型と同じ型ということになります。
このtypedefという機能を構造体に使うとひとつの構造体型を作成することができます。
次の例では、positionという型を作成しています。
typdef struct tag_position
{
int x;
int y;
int z;
} position;
main()
{
position pst;
pst.x = 1;
pst.y = 2;
pst.z = 3;
次のQUEUE型は、構造体メンバーに自分自身であるQUEUE型へのポインタを2つもつ構造となっています。これは、データ構造のひとつである待ち行列(キュー)を管理するための構造体です。
typedef struct queue{ //キュー
struct queue *next; //next pointer
struct queue *prev; //previos pointer
} QUEUE;
共用体
構造体と似たような形式をしているもので共用体というものがあります。
文字通り、共用体は、領域を「共用」するデータ構造です。
具体的に次の例でみていきます。
typedef union tag_data
{
unsinged char ch[4];
unsinged short sh[2];
unsinged long ln;
}data;
main()
{
data dt;
dt.ln = 0x12345678;
この例では、共用体のdata型は、4バイトの領域をもつ型となります。
その4バイトの領域を共用体のメンバーであるch、sh、lnでそれぞれアクセスすることができます。構造体と違う点は、この領域が共通した領域であるということです。
上記のプログラムでは、lnを使って0x1234568という値を代入しています。
この値は、4バイトデータとして保持されていて、共用体のメンバーであるch、sh、lnによってデータの取り出し方を変えることができます。
複数バイトのデータ保持の仕方は、プロセッサによって異なるのですが、インテル系プロセッサ(主にWindows PC)では、次のような形式で保持されます。この形式をリトルエンディアンと呼んでいます。
共用体ch[0]を読むと0x78(16進数で78)、ch[1]を読むと0x56となります。
また、sh[0]を読むと0x5678、sh[1]を読むと0x1234が読みだされます。
ちなみに、モトローラ系と呼ばれるプロセッサ(主に組み込みシステムに使われるプロセッサ)では、複数バイトデータは、ビックエンディアン形式で保存されます。
この場合は、次のようにデータが並びます。
ビックエンディアン形式の場合、データと保存領域がストレートなのでわかりやすいかと思います。
このように、プロセッサによってデータの格納に差が出る点は注意が必要ですが、いずれにしても、共用体は、共通のデータ領域に対してアクセス方法を変えたいときに使います。
ビットフィールド
ここまでで扱った構造体のメンバーは、バイト区切りでしたが、これをビット区切りにすることができます。
一般的にビットフィールドと呼ばれますが、このビットフィールドによって、構造体のメンバーをビットごとに割り当てることができます。
ビットフィールドは、各メンバーに対して次のように記述します。
メンバーの型 構造体メンバー名 : ビット数;
これにより、構造体メンバーに指定のビットが割り当てられます。
typedef struct tag_ctlrg
{
unsinged char bit0 : 1;
unsinged char bit1 : 1;
unsinged char bit2 : 1;
unsinged char bit3 : 1;
unsinged char bit4 : 1;
unsinged char bit5 : 1;
unsinged char bit6 : 1;
unsinged char bit7 : 1;
}ctlrg;
上の例では、構造体ctlrgのメンバーbit0からbit7までにそれぞれ1ビットずつ領域が割り当てられることになります。
ビットフィールドは、フラグ操作や組み込みシステムのレジスタ操作でよく使用されます。
コメント