# 電気回路が分からなくても分かるC言語のUnionとStructの違い
tags: 情報
もう電気回路なんてしないなんて言わないよ絶対(なんて言わないよ絶対)
電気回路←うわぁ
前回インターンしようと思った会社のCTOが電気系でうわぁ...と思ったら案の定落ちていました.
もう電気のことなんか考えたくもないのでC言語の話をします.
UnionとStruct
なんかこいつら(union
とstruct
)似てないか?と思う人もたくさんいると思います.
ちなみに去年の今頃は僕もそう思っていませんでした.というか自分が授業をやるならアルゴリズムとかよりもこういう似ている気がするけど実際は違うものの違いを聞くと思います.
まぁそんなことはさておき,こいつらの違いはアドレスを出力してしまえば簡単に分かります.
下のようなコードを書きます.
#include <stdio.h> #include <stdint.h> typedef union union_t { int8_t i8; int16_t i16; int32_t i32; int64_t i64; } myUnion; typedef struct struct_t { int8_t i8; int16_t i16; int32_t i32; int64_t i64; } myStruct; int main (void) { myUnion u; myStruct s; printf("Address\n"); printf("\n"); printf("Union's i8 = %p, i16 = %p, i32 = %p, i64 = %p\n", &(u.i8), &(u.i16), &(u.i32), &(u.i64)); printf("Struct's i8 = %p, i16 = %p, i32 = %p, i64 = %p\n", &(s.i8), &(s.i16), &(s.i32), &(s.i64)); printf("-------------\n"); printf("Union & Struct's Size\n"); printf("\n"); printf("myUnion's size = %zu\n", sizeof(myUnion)); printf("myStruct's size = %zu\n", sizeof(myStruct)); printf("-------------\n"); printf("Sizes of types\n"); printf("\n"); printf("i8 = %zu, i16 = %zu, i32 = %zu, i64 = %zu\n", sizeof(int8_t), sizeof(int16_t),sizeof(int32_t), sizeof(int64_t)); return 0; }
こいつをgcc
でコンパイルして実行してやると以下のような出力を得ます.
Address Union's i8 = 0x7fffbb250d48, i16 = 0x7fffbb250d48, i32 = 0x7fffbb250d48, i64 = 0x7fffbb250d48 Struct's i8 = 0x7fffbb250d50, i16 = 0x7fffbb250d52, i32 = 0x7fffbb250d54, i64 = 0x7fffbb250d58 ------------- Union & Struct's Size myUnion's size = 8 myStruct's size = 16 ------------- Sizes of types i8 = 1, i16 = 2, i32 = 4, i64 = 8
出力解説
Address
の出力から分かるようにunion
はアドレスが全て同じで,struct
はアドレスが全て違います.
次にUnion & Struct's Size
を見てみます.ここからは(当然?)使っているメモリの大きさが異なります.
最後に各型の大きさが違うことが分かります.
結論から言ってしまうと,union
はメンバーの型のうち最大のもののメモリ領域を確保して,メンバーのいずれかに値を格納します.
一方,struct
はメンバー変数のメモリ領域をそれぞれ確保して,それぞれに別々の値を格納します
図示すると下のようになります.
Padding
ただ,今回全てのtypeの大きさを足すと1 + 2 + 4 + 8 = 15
bytesです.しかし,myStruct
の大きさは16 bytesです.
C言語では処理系(gcc
やclang
など)によってパッディング(アラインメント)2と言って構造体内の奇数の大きさの型の大きさを偶数にすることがあります.
ここではint8_t
が1 byteなのでパッディングされて2 bytesになっているのでしょう.
まとめ
union
は複数の型を選んで使えるようにメモリを共有しているstruct
は複数の型を同時に格納できるようにそれぞれにメモリを格納している- パッディング(アラインメント)によってメモリの和がそのまま
struct
のメモリの大きさになるわけではない - 電気回路を二度と勉強したくない