C言語における共用体・列挙型・ビット演算の基本構造とメモリ管理

1. 共用体(union)の定義とメモリ構造

共用体は、複数のメンバが同一のメモリ領域を共有するためのデータ構造です。構造体とは異なり、ある時点で有効なメンバは1つのみとなります。

主な特徴

  • メモリ共有: すべてのメンバが同じ開始アドレスを共有します。
  • サイズ計算: 共用体のサイズは、最大のメンバのサイズに基づいて決定されます。
  • メモリ境界調整(アライメント): 最大の型サイズの整数倍になるよう、パディングが追加されることがあります。
#include <stdio.h>
#include <string.h>

union Storage {
    int ival;
    double dval;
    char text[20];
};

int main() {
    union Storage node;

    // サイズの確認(最大のメンバ text[20] と double のアライメントを考慮)
    printf("共用体のサイズ: %zu バイト\n", sizeof(node));

    // int型として使用
    node.ival = 1024;
    printf("int: %d\n", node.ival);

    // double型として使用(intの値は破壊される)
    node.dval = 3.14159;
    printf("double: %.5f\n", node.dval);

    // 文字列として使用
    strcpy(node.text, "C-Language");
    printf("text: %s\n", node.text);

    return 0;
}

2. 列挙型(enum)による定数管理

列挙型は、整数定数に名前を付けて管理するための型です。コードの可読性を高めるのに有効です。

列挙型の規則

  • デフォルトでは最初の要素が0から始まり、以降1ずつ増加します。
  • 任意の値を手動で割り当てることが可能です。値を指定しない場合、直前の要素の値+1となります。
  • 列挙型のメンバは定数であるため、ドット演算子によるアクセスなどは行いません。
#include <stdio.h>

enum DeviceStatus {
    IDLE,          // 0
    CONNECTING = 5, // 5
    CONNECTED,     // 6
    DISCONNECTING, // 7
    ERROR = -1     // -1
};

int main() {
    enum DeviceStatus current = CONNECTED;

    if (current == CONNECTED) {
        printf("ステータス値: %d\n", current);
    }

    return 0;
}

3. ビット演算子の活用

ビット単位の操作を行うことで、メモリ節約や高速な計算、フラグ管理が可能になります。

主要な演算子

  • & (論理積): 両方のビットが1の場合のみ1。特定のビットを「抽出」したり「クリア」するのに使用。
  • | (論理和): 少なくとも一方のビットが1なら1。特定のビットを「セット」するのに使用。
  • ^ (排他的論理和): ビットが異なる場合のみ1。値の反転や入れ替えに使用。
  • ~ (否定): ビットを反転。
  • << (左シフト): 1ビットシフトするごとに値を2倍にする。
  • >> (右シフト): 1ビットシフトするごとに値を1/2にする。

排他的論理和(^)を用いた変数スワップ

#include <stdio.h>

int main() {
    int x = 10, y = 20;

    // 一時変数を使わないスワップ
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;

    printf("x: %d, y: %d\n", x, y); // x=20, y=10
    return 0;
}

4. 構造体と共用体のネストによるメモリ計算

メモリサイズを計算する際は、アライメント規則に注意が必要です。以下の例では、各メンバがどのようにメモリを占有するかを考慮します。

#include <stdio.h>

struct Record {
    union {
        char tag[5];  // 5バイト
        short code[2]; // 4バイト
    } header;         // 共用体サイズは最大要素の5バイトだが、short(2)のアライメントで6バイト

    char name[10];    // 10バイト
    float score;      // 4バイト
};

/*
計算例 (アライメント単位を4とした場合):
1. header: 6バイト (アライメント調整含む)
2. name: 10バイト
3. 調整: 16バイト経過後、float(4バイト)は4の倍数位置から開始可能
4. score: 4バイト
合計: 6 + 10 + 4 = 20バイト
*/

構造体内の共用体は、データプロトコルや可変長メッセージのパースにおいて非常に強力なツールとなります。ビットフィールドと組み合わせることで、ハードウェア制御に近いレイヤーでの実装も容易になります。

タグ: c-language Memory-Management bitwise-operations data-structures

10月6日 06:23 投稿