*C言語* 〜41時限目〜 ビットフィールドを使う・・・
〜目次〜
ビットフィールドを使う
構造体のサイズに影響を与える、
ビットフィールド(bit field)
というメンバについて学んでいきます。
構造体のメンバの中には、
取りうる値の範囲が狭くて済むものがあります。
以下のような構造体の宣言、
小さなサイズのメンバを宣言することができます。
typedef struct Car1{
int num;
double gas;
unsigned int tire : 3; (3ビットのメンバ)
unsigned int roof : 1; (1ビットのメンバ)
unsigned int color : 4; (4ビットのメンバ)
}Car1;
3つのメンバの最後には「:O」という記述があります。
これは、
「指定したメンバをOビットにする」
という意味を持っています。
このように、
ビットを指定したメンバのことを、
「ビットフィールド」と呼びます。
例えばtireは3ビットなので、8種類の値を格納できます。
このように取りうる値が少ないメンバは、
ビットフィールドとしておくと便利です。
ビット数を指定しておくと、
構造体全体のサイズを小さくし、
メモリを節約できる可能性があるからです。
実際にビットフィールドを使ってコードを入力します。
sample94.c
ーsample94の実行画面ー
ビットフィールドを使った構造体のサイズは24バイトです。
ビットフィールドを使わない構造体のサイズは32バイトです。
sample94では、2種類の構造体を宣言しています。
Car1はビットフィールドを使った構造体型です。
Car2はビットフィールドを使わない構造体型です。
sizeof演算子と使って、2つの型のサイズを調べています。
実行画面をみてわかる通り、
メンバをビットフィールドとしておくことで、
構造体全体のサイズを小さくすることができる可能性があります。
構造体のサイズは、各メンバのサイズを足し合わせたものになるとは限りません。
なので、
ビットフィールドを使っても、
常に全体のサイズを小さくできる訳ではないのです。
使っている実行環境によって結果は異なります。
引数として構造体を使う
構造体を関数の中で使う方法について見ていきます。
構造体は、関数の引数として利用することができます。
sample95.c
ーsample95の実行画面ー
ナンバーを入力してください。
7777
ガソリン量を入力してください。
12.3
車のナンバーは7777:ガソリン量は12.300000
引数は原則として値渡しで関数内に渡されます。
構造体を引数とした場合も、「値」が渡されます。
これは、
実引数の構造体のメンバの値がそれぞれコピーされて、
関数の本体に渡される
ということを意味しています。
つまり、
ここでは構造体のメンバであるnumとgasの値が、
コピーされて関数に渡されるようになっているのです。
構造体へのポインタを引数に使う
メンバがたくさんある構造体を引数として使う場合には、
注意が必要になります。
関数を呼び出すたびに、
たくさんのメンバがコピーされるため、
関数の呼び出しに時間がかかってしまうことがあります。
このため、
大きな構造体を関数の引数として利用する場合、
構造体ではなく、
構造体へのポインタを引数として使う
ことがあります。
つまり、
構造体型の変数のアドレスを使うようにするのです。
構造体へのポインタを関数の引数としておくと、
アドレスを渡すだけで関数が呼び出されます。
構造体へのポインタの方が構造体よりもサイズが小さいということは、
すでに学びました。
なので、
構造体へのポインタを使った方が、
処理速度が向上する場合があります。
尚、ポインタで渡した場合は引数を実質的に参照渡しとすることになるので、
渡した構造体のメンバの値を関数内で変更することができます。
ただし、このような関数内では、
構造体へのポインタを使って各メンバにアクセスする、
処理を記述しなくてはいけません。
ポインタからメンバにアクセスする場合には、
アロー演算子(ー>)
を用いると便利です。
実際に引数として構造体へのポインタを渡す、
コードを入力して見ます。
sample96.c
ーsample96の実行画面ー
ナンバーを入力してください。
7777
ガソリン量を入力してください。
12.3
車のナンバーは7777:ガソリン量は12.300000
この関数内ではポインタが渡されるので、
メンバにアクセスする場合には、
〜END〜