共用体
2018/10/23 - moriya - ~2 Minutes
さて、構造体の次に出てくるのが共用体だろう。
これが、今思うと、自分には、超難解だった。ネット上の説明も、まあまあ、デタラメだと思う。
私がこれまで携わってきた中では、以下の二つのケースが大半だったので、私見だが、使う必要が出てきた時に考えればよいと思う。
可変サイズのデータの格納
typedef union {
char charval;
int intval;
long longval;
double doubleval;
} variant_t;
int main(int argc, char *argv[])
{
variant_t v;
v.charval = 1;
v.intval = 2;
v.longval = 3;
}
一般的には、こういう説明だろう。
図示すると次のようになるだろうか。
しかし、ネット上の説明がデタラメだと思うのは、いったい、どの共用体メンバーにアクセスしてよいかわからない点だ。
実際には、構造体と組み合わせて使うのではないかと思う。
#include <stdio.h>
// char でも int でも long でも double でも入るデータ構造を考えてみる
typedef struct {
int valtype; // 1=charval, 2=intval, 3=longval、 4=doubleval
union {
char charval;
int intval;
long longval;
double doubleval;
} u;
} variant_t;
int
main(int argc, char *argv[])
{
variant_t v;
v.valtype = 3;
v.u.longval = 1234567890;
switch (v.valtype) {
case 3:
printf("%ld\n", v.u.longval);
break;
default:
printf("not implemented yet\n");
break;
}
return 0;
}
おそらく、こういった、データの中身に何が入ってもよいような構造を作りたい場合に union を使うことがあるかもしれない。
もちろん、ベタに、
typedef struct {
int valtype; // 1=charval, 2=intval, 3=longval、 4=doubleval
struct {
char charval;
int intval;
long longval;
double doubleval;
} s;
} variant_t;
とか、
typedef struct {
int valtype; // 1=charval, 2=intval, 3=longval、 4=doubleval
char charval;
int intval;
long longval;
double doubleval;
} variant_t;
でもよいのだが、不要なメモリを確保してしまうことになるので、通信など、サイズに制約があるようなデータは、union のようなデータ構造になっているだろう。
ビットフィールド
組み込み用のマイコンでは、ある領域を、バイト単位でもビット単位でもアクセスしたい場合があり、そういった場合に union を使うことも多い。
#include <stdio.h>
#include <stdint.h>
typedef union {
struct {
unsigned int b7: 1;
unsigned int b6: 1;
unsigned int b5: 1;
unsigned int b4: 1;
unsigned int b3: 1;
unsigned int b2: 1;
unsigned int b1: 1;
unsigned int b0: 1;
} bit;
uint8_t byte;
} reg_t;
int
main(int argc, char *argv[])
{
reg_t reg;
reg.byte = 0xaa;
// ベタでごめん
printf("%d ", reg.bit.b7);
printf("%d ", reg.bit.b6);
printf("%d ", reg.bit.b5);
printf("%d ", reg.bit.b4);
printf("%d ", reg.bit.b3);
printf("%d ", reg.bit.b2);
printf("%d ", reg.bit.b1);
printf("%d\n", reg.bit.b0);
return 0;
}