Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

構造体の概念で理解するC言語のビットフィールド|定義方法と範囲の計算を徹底解説

ビットフィールドとは

ビットフィールドとは、変数が占めるメモリのサイズをビット単位で指定できるC言語の機能です。通常は構造体(struct)の中で定義されます。

  • ビットフィールドの基本:1バイト=8ビット

記述例

struct info {
    int x : 2;
};

この例では、メンバxは2ビットを占有します。

ビットフィールド使用時の注意点

  • ビットフィールドの範囲外の値を代入することはできません(その場合の動作は保証されません)。
  • sizeof演算子やアドレス演算子(&)をビットフィールドに適用できないため、scanf関数で値を入力することもできません。
  • ビットフィールドに指定できるデータ型は、int、signed int、unsigned intです。

unsigned int を使ったプログラム

以下は、unsigned intにビットフィールドを割り当てたCプログラムです。

#include <stdio.h>

struct info {
    unsigned int x : 3; // 構造体内でunsigned intにビットフィールドを割り当て
};

int main(void) {
    struct info i;
    i.x = 8;
    printf("%d", i.x);
    return 0;
}

実行結果

0

解説

  • unsigned intの値の範囲は「0 ~ 2<sup>n</sup> − 1」です(nはビット数)。
  • このプログラムでは n = 3 なので、扱える範囲は 0 ~ 2<sup>3</sup> − 1、すなわち 0 ~ 7 となります。
  • 範囲外の値 8 を代入すると、下位3ビット(000)だけが保持されるため、出力は 0 になります。

構造体の概念で理解するC言語のビットフィールド|定義方法と範囲の計算を徹底解説

int(符号付き整数)を使ったプログラム

次に、intにビットフィールドを割り当てた場合のプログラムを見てみましょう。

#include <stdio.h>

struct info {
    int x : 3; // 構造体内でintにビットフィールドを割り当て
};

int main(void) {
    struct info i;
    i.x = 4;
    printf("%d", i.x);
    return 0;
}

実行結果

-4

解説

  • signed int(符号付き整数)の値の範囲は「−2<sup>n−1</sup> ~ 2<sup>n−1</sup> − 1」です(nはビット数)。
  • このプログラムでは n = 3 なので、範囲は −4 ~ 3 となります。
  • 範囲外の値 4 を代入すると、3ビットのパターン「100」は2の補数表現で −4 を表すため、出力は −4 になります。

まとめ

ビットフィールドを使えば、構造体のメンバが消費するメモリをビット単位で細かく制御できます。ただし、int・signed int・unsigned intそれぞれの表現可能な範囲を正しく把握し、範囲外の値を代入しないよう注意することが重要です。

  1. C言語におけるユニオンとポインタの使い方を徹底解説

    ユニオン(共用体)とは、異なるデータ型を持つ複数の変数が、同一のメモリ領域を共有するための仕組みです。構造体が各メンバーごとに独立したメモリを割り当てるのに対し、ユニオンではすべてのメンバーが同じアドレスを参照するという点が大きな特徴です。 ユニオンの構文 ユニオンを定義するときの基本的な書式は次の通りです。 union タグ名{ データ型 メンバー1; データ型 メンバー2; ---- ---- データ型 メンバーn; }; 実際の記述例を見てみましょう。 union sample{ int a; float b; char

  2. C言語のポインタ入門!宣言・初期化から配列アクセスの実例まで徹底解説

    ポインタ(pointer)とは、他の変数のメモリアドレスを格納するための変数です。C言語においてポインタは、メモリを直接操作したり、関数間でデータを効率的にやり取りしたりするために欠かせない重要な概念です。 ポインタの宣言・初期化とアクセス まず、次のような通常の整数変数の宣言を見てみましょう。 int qty = 179; 変数qtyには値「179」が格納されると同時に、メモリ上のどこかにその格納場所(アドレス)が割り当てられます。 ポインタの宣言 int *p; 「p」はポインタ変数であり、別の整数型(int)変数のアドレスを保持します。変数名の前にアスタリスク(*)を付けることで、「こ