「C言語キーワード一覧」を見ると、まだ説明していない命令が2つあります。
union |
と
volatile |
です。
今回は、共用体(union)について説明します。
union については「小数の表現4」で一度使いました。
共用体とは、1つのアドレスに複数の名前が付けられるというものです。
まずは1つプログラムを書いてみます。
<sample program 182-01>
#include <stdio.h>
union Sample {
int data1;
int data2;
};
int main(void)
{
union Sample sample;
return 0;
}
|
基本的には構造体と同じ宣言方法です。
※typedefも使えます。
こう宣言した場合のメモリの状態を図にしてみます。
+------------*
sample.data1 | | ← sample.data2でもある
+------------*
イメージするのが難しいと思いますので、プログラムを追加します。
<sample program 182-02>
#include <stdio.h>
union Sample {
int data1;
int data2;
};
int main(void)
{
union Sample sample;
sample.data1 = 15;
printf("data = %d\n", sample.data2);
return 0;
}
|
<実行結果>
data2 = 15 続行するには何かキーを押してください・・・
15は data1 に入れたはずですが、data2 に15が入っています。
共用体では、data1 も data2 も同じメモリ領域を指しています。
と言う事は、data1 に 入れたデータは data2 にも入っていると言う事です
要はメモリ領域は1つしか確保されておらず、名前だけが2つ付いています。
しかし、重要なのは「使い道」です。
正直、私自身は余り使う場面がありません・・・
「エンディアン」の説明をしなければならない時くらいでしょうか。
「エンディアン」とは何か、先にプログラムを書いて動かしてみましょう。
<sample program 182-03>
#include <stdio.h>
union Sample {
long data;
unsigned char byte[4];
};
int main(void)
{
union Sample sample;
sample.data = 0x89ABCDEF;
printf("data = %08X\n", sample.data);
return 0;
}
|
<実行結果>
data = 89ABCDEF 続行するには何かキーを押してください・・・
今回は、共用体のメンバ変数の型を変えてみました。
longは私の環境では32ビットです。
unsigned charは4つの配列になっていますので、8ビット×4で32ビットです。
これをメモリの図として書いてみます。
+------------*
sample.data | | sample.byte[0]
+------------*
| | sample.byte[1]
+------------*
| | sample.byte[2]
+------------*
| | sample.byte[3]
+------------*
1バイトごとにアドレスが割り振られていますので、↑の図のようになります。
では、実際の中身はどうなっているのでしょうか。
<sample program 182-04>
#include <stdio.h>
union Sample {
long data;
unsigned char byte[4];
};
int main(void)
{
union Sample sample;
sample.data = 0x89ABCDEF;
printf("data = %08X\n", sample.data);
printf("byte[0] = %02X\n", sample.byte[0]);
printf("byte[1] = %02X\n", sample.byte[1]);
printf("byte[2] = %02X\n", sample.byte[2]);
printf("byte[3] = %02X\n", sample.byte[3]);
return 0;
}
|
<実行結果>
data = 89ABCDEF byte[0] = EF byte[1] = CD byte[2] = AB byte[3] = 89 続行するには何かキーを押してください・・・
と言う事は、メモリの中身は、
+------------*
sample.data | EF | sample.byte[0]
+------------*
| CD | sample.byte[1]
+------------*
| AB | sample.byte[2]
+------------*
| 89 | sample.byte[3]
+------------*
となっています。
順番に並べてみると、
EF CD AB 89
になっており、バイト単位で考えるとデータが逆に入っています。
何となくですが、
89 AB CD EF
というデータは、
+------------*
sample.data | 89 | sample.byte[0]
+------------*
| AB | sample.byte[1]
+------------*
| CD | sample.byte[2]
+------------*
| EF | sample.byte[3]
+------------*
と格納されているように思えます。
しかし、私の環境では逆でした。
この「エンディアン」というのは、データをメモリに格納する際の順番の事です。
私の環境の、
+------------*
sample.data | EF | sample.byte[0]
+------------*
| CD | sample.byte[1]
+------------*
| AB | sample.byte[2]
+------------*
| 89 | sample.byte[3]
+------------*
この状態を「リトルエンディアン」と言い、
+------------*
sample.data | 89 | sample.byte[0]
+------------*
| AB | sample.byte[1]
+------------*
| CD | sample.byte[2]
+------------*
| EF | sample.byte[3]
+------------*
こちらを「ビッグエンディアン」と言います。
これは、CPUによっても違う可能性がありますし、ネットワーク上で扱われるデータでも違いがあります。
プログラムを移植するとか、ネットワーク上でデータを扱う等、状況に応じて「エンディアン」を確認していく必要があります。