Nodachisoft Nodachi Sword Icon
  
@あまじ✎ 2021年3月3日に更新

第2章48 共用体(union)を使う

イチからゲーム作りで覚えるC言語
第2章47 リスト構造 : PREV
NEXT : 第2章49 ソートの仕組み(バブルソート) :

概要

C言語の共用体(union)の使い方について確認していきましょう。

共用体は同じメモリアドレスに対して、異なる変数や型でアクセスできる機能です。

共用体は小さいメモリ領域をビット単位で有効活用する時にも利用できます。

共用体の書き方

共用体(union)の書き方は構造体(struct)の書き方とほぼ同じです。

共用体の定義
union 共用体の名前 { …共用体の構造… };

共用体の中身の定義の一つ一つをメンバと呼びます。

共用体は、メンバは同じメモリアドレスを参照します。

例えば、下のように共用体を定義してみるると、

 
union_ex0.c
union PlayerName {
    char name[64];
    char namecap;	// 名前
};

共用体のメンバ name と、メンバ namecap は同じメモリアドレスを指します。

共用体のメンバへのアクセス方法は構造体と同じで、 変数のメンバには、変数名.メンバ名でアクセスできます。

共用対のポインタ変数から、メンバにアクセスするには -> の記号を使い、変数名->メンバ名でアクセスできます。

共用体の例

共用体の基本的な使い方を確認してみます。

 
union_ex1.c
#include <stdio.h>
typedef union aaa {
    char name[8];
    char namecap;
} PlayerName;

int main() {
    PlayerName player1;
    strcpy( player1.name, "planc");
    printf("名前は:%s \n", player1.name );
    printf("名前の頭文字は:%c \n", player1.namecap );
}

実行した結果は下のようになります。

実行結果
名前は:planc
名前の頭文字は:p

内容を確認しいていきましょう!

 
union_ex1.c
typedef union aaa {
    char name[8];
    char namecap;
} PlayerName;

2~5行目で共用体 aaa を定義しており、aaa は2つのメンバ name, namecap を持っています。 typedef プリプロセッサ命令により、「union aaa」の代わりに「PlayerName」で この型を使うことができるように定義しています。

 
union_ex1.c
int main() {
    PlayerName player1;
    strcpy( player1.name, "planc");

8 行目で、共用体 PlayerName 型の変数 player1 を宣言しています。 9 行目では strcpy という関数を使って、 planer1.name の中に文字列をコピー(代入)しています。 (※strcpy 関数については初めて登場しますが、後ほど文字列を操作するページにてより細かな内容を説明しております)

このとき、player1 の変数の中身は下のようになっています。

union_ex1.png

続いて、10、11 行目で共用対の変数 player1 のメンバにアクセスしています。

 
union_ex1.c
printf("名前は:%s \n", player1.name );
printf("名前の頭文字は:%c \n", player1.namecap );

どちらも同じメモリアドレスを指しており、 player1.namecap は player1.name の先頭 1 文字だけにアクセスすることになります。

ビットフィールドの利用

ビットフィールドと共用体を組み合わせて使うことで、 よりビット単位で扱いやすくすることができます。

※ビットフィールド自体の使用方法はコチラのページからご確認ください。

例えば下のような共用体を定義します。

 
union_ex2.c
#include <stdio.h>
typedef union {
    struct {
        unsigned int isPoison : 1;  // 毒状態
        unsigned int isSleep : 1;   // 睡魔状態
        unsigned int isBlind : 1;   // 視力低下状態
        unsigned int isPowerup : 1; // 強化状態
    } cs;
    char data;
} CharacterStatus;

int main() {
    CharacterStatus player;
    player.cs.isPoison = 1;
    player.cs.isSleep = 0;
    player.cs.isBlind = 0;
    player.cs.isPowerup = 1;
    printf("ステータスのデータは「%d」です。\n", player.data);
}

実行結果は下のようになります。

実行結果
ステータスのデータは「-55」です。

RPGなどでよくある、「毒状態」「睡魔状態」「視力低下状態」「強化状態」の 4種類のステータスを 0 か 1 で管理する、構造体のデータを 1 バイト単位で簡単に取り出したり、読み込んだりするための共用体を例にしてみました。

CharacterStatus 共用体の定義を確認してみましょう。

 
union_ex2.c
typedef union {
    struct {
        unsigned int isPoison : 1;  // 毒状態
        unsigned int isSleep : 1;   // 睡魔状態
        unsigned int isBlind : 1;   // 視力低下状態
        unsigned int isPowerup : 1; // 強化状態
    } cs;
    char data;
} CharacterStatus;

共用体の中身として、構造体のメンバ変数は cs と、char型のメンバ変数 data の二つがあります。 この二つは同じメモリアドレスを指していることになります。

構造体のメンバ変数 cs の内訳(メンバ)には 4 つの int 型が入っており、それぞれビットフィールドとして 1 ビットが指定されています。

この CharacterStatus 型を利用している、main 関数の箇所を確認します。

 
union_ex2.c
int main() {
    CharacterStatus player;
    player.cs.isPoison = 1;
    player.cs.isSleep = 0;
    player.cs.isBlind = 0;
    player.cs.isPowerup = 1;
    printf("ステータスのデータは「%d」です。\n", player.data);
}

構造体のメンバにそれぞれ値を代入しています。 その後、18 行目で player.data にアクセスしています。 この player.data は player.cs の中身と同じメモリアドレスを指しているので、 player.data の char 型(8 ビット)の中に、player.cs のステータスを表す 4 ビットぶんが 含まれて取得できます。

player.data の値は「-55」であり、この値を保存しておき、あとから player.data に読み込ませれば、 player.cs も一気に保存した内容をロードすることができます。

参考

(英語)N1570 - 5.1.2.2.1 Program startup

イチからゲーム作りで覚えるC言語
第2章47 リスト構造 : PREV
NEXT : 第2章49 ソートの仕組み(バブルソート) :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

第4章3 C言語コンソール上で迷路脱出プログラム・迷路の自動生成

#C11仕様#C言語#ゲームプログラミング✎ 2021-05-15
C言語のコンソールゲームで迷路脱出ゲームプログラムの作り方を確認します。迷路は自動生成されます
広告領域
追従 広告領域
目次
第2章48 共用体(union)を使う
第2章48 共用体(union)を使う
概要
概要
共用体の書き方
共用体の書き方
共用体の例
共用体の例
ビットフィールドの利用
ビットフィールドの利用
参考
参考
Nodachisoft © 2021