C言語プログラミングにおける連合体union入門学習チュートリアル
6775 ワード
ユニオン(union)はC言語で特殊なデータ型であり、異なるタイプのデータを同じメモリ位置に格納することができる.複数のメンバーを使用する連合体を定義できますが、1つのコンポーネントだけがいつでも指定された値を含むことができます.共同体は、同じメモリ位置を用いて多用途に有効な方法を提供する.
連合体を定義連合体を定義するには、union文を使用して構造を定義するのと似ている必要があります.連合体宣言には、プログラムが1つ以上のメンバーを持つ新しいデータ型が定義されています.連合体宣言の形式は次のとおりです.
Unionラベルはオプションで、各メンバーの定義はint iなどの正常な変数定義です.およびfloat f;または他の有効な変数の定義.連合体定義の末尾、最後のセミコロンの前に、1つ以上の変数の連係を指定できますが、オプションです.ここでは、データ・コンビネーション・タイプという3つのメンバーi,f,strを定義します.
データ型の変数に格納できる整数、浮動小数点数、または文字列.これは、1つの単一の可変構造、すなわち、同じ記憶ユニットが、複数のタイプのデータを記憶するために使用できることを意味する.任意の組み込みまたはユーザー定義のデータ型を使用して、必要に応じて統合できます.
unionによって消費されるメモリは、コンビネーションの最大メンバーを収容するのに十分な大きさになります.例えば、上記の例のデータ型は、文字列によって占有される最大の空間であるため、20バイトの記憶領域を占有する.以下に、上述した統合型のメモリサイズの例を示します.
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
連合体メンバーにアクセス連合体の任意のメンバーにアクセスするには、メンバーアクセス演算子(.)を使用します.メンバー・アクセス演算子は、連合体変数名とメンバーとして符号化され、unionキーを使用して連合体タイプの変数を定義します.以下に、連合体の使用例を示します.
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
ここで、strメンバーの値が良好に印刷された場合、変数の最終値が占有されたメモリ位置に割り当てられたため、連合体メンバーiとfの値が破損していることがわかります.次に、同じ例をもう一度見てみましょう.同じ時間に変数を使用します.これは連合体の主な目的です.
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
ここでは、1つの部品が一度に使用されるため、すべてのメンバーが非常によく印刷されています.
アプリケーションの場合、複数のデータを共有する必要がある場合や、複数のデータを毎回一時的に取得する必要がある場合は、コンビネーション(union)を利用することができます.C Programming Languageという本では、連合体についてこう述べています.
1)連合体は構造である;
2)そのすべてのメンバーのベースアドレスに対するオフセット量は0である.
3)この構造空間は、最も「幅の広い」メンバーを収容するのに十分な大きさである.
4)すべてのメンバーに合わせるように配置されます.
次の4つの説明を説明します.
コンビネーション内のすべてのメンバーはメモリを共有しているため、各メンバーの格納ヘッダアドレスは、コンビネーション変数のベースアドレスに対するオフセット量が0であり、すなわち、すべてのメンバーのヘッダアドレスが同じである.すべてのメンバーがメモリを共有できるようにするには、これらのメンバーの中で最も広いメンバーを収容するのに十分なスペースが必要です.この「整列はすべてのメンバーに適合する」とは、すべてのメンバーの自己整列に適合する必要があることを意味します.
次に例を示します.
例えば連合体
sは9バイト、nは4バイト、dは8バイトであるため、少なくとも9バイトの空間が必要である.しかし、実際のサイズは9ではなく、演算子sizeofでそのサイズが16であることをテストしたのは、ここでバイト整列の問題があり、9は4でも8でも整列できないためである.したがって、バイトは16に追加され、すべてのメンバーの自己整列に合致します.ここから、連合体が占める空間は、最も広いメンバーに依存するだけでなく、すべてのメンバーと関係があることがわかります.すなわち、その大きさは2つの条件を満たす必要があります.1)最も広いメンバーを収容するのに十分な大きさです.2)サイズは、含まれるすべての基本データ型のサイズによって割り切れる.
試験手順:
出力結果:
sizeof(u 1)=16の場合.u 1ではsが9バイト,nが4バイト,dが8バイトであるため,少なくとも9バイトが必要である.基本データ型はchar,int,doubleがそれぞれ1,4,8バイトを占め,u 1が占める空間の大きさを1,4,8で割り切るためには16バイトを埋める必要があるためsizeof(u 1)=16.
sizeof(u 2)=8の場合.u 2ではsが5バイト,nが4バイト,dが8バイトであるため,少なくとも8バイトが必要である.基本データ型はchar,int,doubleがそれぞれ1,4,8バイトを占め,u 2が占める空間の大きさを1,4,8で割り切るためにバイトを埋め込む必要はなく,8自体が要求を満たすためである.したがってsizeof(u 2)=8である.
印刷された各メンバーのベースアドレスから、連合体内の各メンバーのベースアドレスは、連合体変数の最初のアドレスと同じであることがわかります.
u 1.n=1に対して、u 1のnを1に割り当てた場合、このセグメントのメモリの最初の4バイトに格納されるデータは、1億1,000,000,000,000,000,000,000,000,000,000,000になります.
したがって、s[0]をとるデータは、1番目のセルをとるデータであり、その整数値が1であるため、印刷結果は1である.
印刷されたdが0.000000である場合、以下のようにしたい.このセグメントのメモリの上位4バイトのセルに格納されているデータは、1億1,000,000,000,000,000,000,000,000であることが知られているため、上からの印刷結果は48204,64,0であり、後の4バイトのセルのデータは、0,10000,11001100,0100億,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
00000000 01000000 11001100 00110000 00000000 00000000 00000000 00000001
double型データの場合、63ビット目は0が符号ビット、62-52億0100が次数符号、11001100億10000000000億円10000000000億円10000000000億円が端数となり、その値から端数値は約0、次数符号は4-1023=-1019となっているため、浮動小数点数は1.0*2^(-1019)=0.00000000000億円…となり、出力結果は0.000000となった.
連合体を定義連合体を定義するには、union文を使用して構造を定義するのと似ている必要があります.連合体宣言には、プログラムが1つ以上のメンバーを持つ新しいデータ型が定義されています.連合体宣言の形式は次のとおりです.
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
Unionラベルはオプションで、各メンバーの定義はint iなどの正常な変数定義です.およびfloat f;または他の有効な変数の定義.連合体定義の末尾、最後のセミコロンの前に、1つ以上の変数の連係を指定できますが、オプションです.ここでは、データ・コンビネーション・タイプという3つのメンバーi,f,strを定義します.
union Data
{
int i;
float f;
char str[20];
} data;
データ型の変数に格納できる整数、浮動小数点数、または文字列.これは、1つの単一の可変構造、すなわち、同じ記憶ユニットが、複数のタイプのデータを記憶するために使用できることを意味する.任意の組み込みまたはユーザー定義のデータ型を使用して、必要に応じて統合できます.
unionによって消費されるメモリは、コンビネーションの最大メンバーを収容するのに十分な大きさになります.例えば、上記の例のデータ型は、文字列によって占有される最大の空間であるため、20バイトの記憶領域を占有する.以下に、上述した統合型のメモリサイズの例を示します.
#include
#include
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
printf( "Memory size occupied by data : %d
", sizeof(data));
return 0;
}
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
Memory size occupied by data : 20
連合体メンバーにアクセス連合体の任意のメンバーにアクセスするには、メンバーアクセス演算子(.)を使用します.メンバー・アクセス演算子は、連合体変数名とメンバーとして符号化され、unionキーを使用して連合体タイプの変数を定義します.以下に、連合体の使用例を示します.
#include
#include
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");
printf( "data.i : %d
", data.i);
printf( "data.f : %f
", data.f);
printf( "data.str : %s
", data.str);
return 0;
}
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming
ここで、strメンバーの値が良好に印刷された場合、変数の最終値が占有されたメモリ位置に割り当てられたため、連合体メンバーiとfの値が破損していることがわかります.次に、同じ例をもう一度見てみましょう.同じ時間に変数を使用します.これは連合体の主な目的です.
#include
#include
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
data.i = 10;
printf( "data.i : %d
", data.i);
data.f = 220.5;
printf( "data.f : %f
", data.f);
strcpy( data.str, "C Programming");
printf( "data.str : %s
", data.str);
return 0;
}
上記のプログラムをコンパイルして実行します.これにより、次の結果が得られます.
data.i : 10
data.f : 220.500000
data.str : C Programming
ここでは、1つの部品が一度に使用されるため、すべてのメンバーが非常によく印刷されています.
アプリケーションの場合、複数のデータを共有する必要がある場合や、複数のデータを毎回一時的に取得する必要がある場合は、コンビネーション(union)を利用することができます.C Programming Languageという本では、連合体についてこう述べています.
1)連合体は構造である;
2)そのすべてのメンバーのベースアドレスに対するオフセット量は0である.
3)この構造空間は、最も「幅の広い」メンバーを収容するのに十分な大きさである.
4)すべてのメンバーに合わせるように配置されます.
次の4つの説明を説明します.
コンビネーション内のすべてのメンバーはメモリを共有しているため、各メンバーの格納ヘッダアドレスは、コンビネーション変数のベースアドレスに対するオフセット量が0であり、すなわち、すべてのメンバーのヘッダアドレスが同じである.すべてのメンバーがメモリを共有できるようにするには、これらのメンバーの中で最も広いメンバーを収容するのに十分なスペースが必要です.この「整列はすべてのメンバーに適合する」とは、すべてのメンバーの自己整列に適合する必要があることを意味します.
次に例を示します.
例えば連合体
union U
{
char s[9];
int n;
double d;
};
sは9バイト、nは4バイト、dは8バイトであるため、少なくとも9バイトの空間が必要である.しかし、実際のサイズは9ではなく、演算子sizeofでそのサイズが16であることをテストしたのは、ここでバイト整列の問題があり、9は4でも8でも整列できないためである.したがって、バイトは16に追加され、すべてのメンバーの自己整列に合致します.ここから、連合体が占める空間は、最も広いメンバーに依存するだけでなく、すべてのメンバーと関係があることがわかります.すなわち、その大きさは2つの条件を満たす必要があります.1)最も広いメンバーを収容するのに十分な大きさです.2)サイズは、含まれるすべての基本データ型のサイズによって割り切れる.
試験手順:
/* 2011.10.3*/
#include
using namespace std;
union U1
{
char s[9];
int n;
double d;
};
union U2
{
char s[5];
int n;
double d;
};
int main(int argc, char *argv[])
{
U1 u1;
U2 u2;
printf("%d
",sizeof(u1));
printf("%d
",sizeof(u2));
printf("0x%x
",&u1);
printf("0x%x
",&u1.s);
printf("0x%x
",&u1.n);
printf("0x%x
",&u1.d);
u1.n=1;
printf("%d
",u1.s[0]);
printf("%lf
",u1.d);
unsigned char *p=(unsigned char *)&u1;
printf("%d
",*p);
printf("%d
",*(p+1));
printf("%d
",*(p+2));
printf("%d
",*(p+3));
printf("%d
",*(p+4));
printf("%d
",*(p+5));
printf("%d
",*(p+6));
printf("%d
",*(p+7));
return 0;
}
出力結果:
16
8
0x22ff60
0x22ff60
0x22ff60
0x22ff60
1
0.000000
1
0
0
0
48
204
64
0
. . .
sizeof(u 1)=16の場合.u 1ではsが9バイト,nが4バイト,dが8バイトであるため,少なくとも9バイトが必要である.基本データ型はchar,int,doubleがそれぞれ1,4,8バイトを占め,u 1が占める空間の大きさを1,4,8で割り切るためには16バイトを埋める必要があるためsizeof(u 1)=16.
sizeof(u 2)=8の場合.u 2ではsが5バイト,nが4バイト,dが8バイトであるため,少なくとも8バイトが必要である.基本データ型はchar,int,doubleがそれぞれ1,4,8バイトを占め,u 2が占める空間の大きさを1,4,8で割り切るためにバイトを埋め込む必要はなく,8自体が要求を満たすためである.したがってsizeof(u 2)=8である.
印刷された各メンバーのベースアドレスから、連合体内の各メンバーのベースアドレスは、連合体変数の最初のアドレスと同じであることがわかります.
u 1.n=1に対して、u 1のnを1に割り当てた場合、このセグメントのメモリの最初の4バイトに格納されるデータは、1億1,000,000,000,000,000,000,000,000,000,000,000になります.
したがって、s[0]をとるデータは、1番目のセルをとるデータであり、その整数値が1であるため、印刷結果は1である.
印刷されたdが0.000000である場合、以下のようにしたい.このセグメントのメモリの上位4バイトのセルに格納されているデータは、1億1,000,000,000,000,000,000,000,000であることが知られているため、上からの印刷結果は48204,64,0であり、後の4バイトのセルのデータは、0,10000,11001100,0100億,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
00000000 01000000 11001100 00110000 00000000 00000000 00000000 00000001
double型データの場合、63ビット目は0が符号ビット、62-52億0100が次数符号、11001100億10000000000億円10000000000億円10000000000億円が端数となり、その値から端数値は約0、次数符号は4-1023=-1019となっているため、浮動小数点数は1.0*2^(-1019)=0.00000000000億円…となり、出力結果は0.000000となった.