型の整列が保証されているunion max_alignの例があります。私の友人を説明するために、共用体が実際に使用されているさらに簡単な例を探しています。
私は通常、テキストを解析するときに共用体を使用します。私はこのようなものを使用します:
typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;
typedef union DataValue
{
int v_int;
float v_float;
char* v_string;
}DataValue;
typedef struct DataNode
{
DataType type;
DataValue value;
}DataNode;
void myfunct()
{
long long temp;
DataNode inputData;
inputData.type= read_some_input(&temp);
switch(inputData.type)
{
case INTEGER: inputData.value.v_int = (int)temp; break;
case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
case STRING: inputData.value.v_string = (char*)temp; break;
}
}
void printDataNode(DataNode* ptr)
{
printf("I am a ");
switch(ptr->type){
case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
case STRING: printf("String with value %s", ptr->value.v_string); break;
}
}
共用体がどのように頻繁に使用されているかを確認したい場合は、 flex / bison を使用してコードを確認してください。たとえば splint を参照してください。これにはたくさんの共用体が含まれています。
私は通常、ユニオンを使用して、データのさまざまなビューを表示したいと考えています。 32ビットvalと赤、緑、青、アルファコンポーネントの両方が必要な32ビットカラー値
struct rgba
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
union
{
unsigned int val;
rgba components;
}colorval32;
注意:ビットマスキングとシフトで同じことを実現することもできます。
#define GETR(val) ((val&0xFF000000) >> 24)
しかし、私は組合のアプローチがよりエレガントだと思います
特定のポートをメモリにマッピングすることにより、レジスタまたはI/Oポートにバイト単位およびビット単位でアクセスするには、以下の例を参照してください。
typedef Union
{
unsigned int a;
struct {
unsigned bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1,
bit8 : 1,
bit9 : 1,
bit10 : 1,
bit11 : 1,
bit12 : 1,
bit13 : 1,
bit14 : 1,
bit15 : 1
} bits;
} IOREG;
# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation
Windowsの世界では、unions
は、 タグ付きバリアント を実装するために一般的に使用されます。 COMオブジェクト間でデータを受け渡す方法 。
union
型は、2つのオブジェクト間で任意のデータを渡すための単一の自然なインターフェースを提供できるという考え方です。一部のCOMオブジェクトは、バリアント(例:type VARIANT
または _variant_t
)double
、float
、int
などを含むことができます。
Windows C++コードでCOMオブジェクトを処理する必要がある場合、いたるところにバリアント型が表示されます。
ユニオンは、さまざまな種類のメッセージがある場合に役立ちます。その場合、中間レベルで正確なタイプを知る必要はありません。送信者と受信者だけがメッセージの実際のメッセージを解析する必要があります。他のレベルでは、サイズと、場合によっては送信者および/または受信者の情報を知るだけで十分です。
struct cat_info
{
int legs;
int tailLen;
};
struct fish_info
{
bool hasSpikes;
};
union
{
fish_info fish;
cat_info cat;
} animal_data;
struct animal
{
char* name;
int animal_type;
animal_data data;
};
SDLはイベントを表すために共用体を使用します: http://www.libsdl.org/cgi/docwiki.cgi/SDL_Event 。
組合が役立つ別の例を次に示します。
(私自身の考えではなく、これは c ++の最適化 について説明しているドキュメントで見つかりました)
begin-quote
....ユニオンは、スペースを節約するためにも使用できます。
最初に非組合アプローチ:
void F3(bool useInt) {
if (y) {
int a[1000];
F1(a); // call a function which expects an array of int as parameter
}
else {
float b[1000];
F2(b); // call a function which expects an array of float as parameter
}
}
ここでは、aとbに同じメモリ領域を使用できます。これは、それらのライブ範囲が重複しないためです。 aとbを結合して結合することで、cpu-cache spaceを大幅に節約できます。
void F3(bool useInt) {
union {
int a[1000];
float b[1000];
};
if (y) {
F1(a); // call a function which expects an array of int as parameter
}
else {
F2(b); // call a function which expects an array of float as parameter
}
}
もちろん、ユニオンの使用は安全なプログラミング手法ではありません。これは、aとbの使用が重複してもコンパイラーから警告が出されないためです。このメソッドは、キャッシュスペースを大量に消費する大きなオブジェクトにのみ使用してください。 ...
end-qoute
このような意味ですか?
union {
long long a;
unsigned char b[sizeof(long long)];
} long_long_to_single_bytes;
[〜#〜]追加[〜#〜]:
私は最近、これをAIXマシンで使用して、64ビットのマシン識別子をバイト配列に変換しました。
std::string getHardwareUUID(void) {
#ifdef AIX
struct xutsname m; // aix specific struct to hold the 64bit machine id
unamex(&b); // aix specific call to get the 64bit machine id
long_long_to_single_bytes.a = m.longnid;
return convertToHexString(long_long_to_single_bytes.b, sizeof(long long));
#else // Windows or Linux or Solaris or ...
... get a 6byte ethernet MAC address somehow and put it into mac_buf
return convertToHexString(mac_buf, 6);
#endif
パーティーに少し遅れていることはわかっていますが、実用的な例として、VBScriptのVariant
データ型はUnion
として実装されていると思います。次のコードは、他の方法で見つかった記事から抜粋した簡単な例です here
struct tagVARIANT
{
union
{
VARTYPE vt;
Word wReserved1;
Word wReserved2;
Word wReserved3;
union
{
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
DATE date;
BSTR bstrVal;
SAFEARRAY *parray;
VARIANT *pvarVal;
};
};
};
(記事に記載されている)実際の実装は、oaidl.hCヘッダーファイルにあります。
私は時々このように共用体を使用しました
//Define type of structure
typedef enum { ANALOG, BOOLEAN, UNKNOWN } typeValue_t;
//Define the union
typedef struct {
typeValue_t typeValue;
/*On this structure you will access the correct type of
data according to its type*/
union {
float ParamAnalog;
char ParamBool;
};
} Value_t;
次に、さまざまな種類の値の配列を宣言し、データを多かれ少なかれ効率的に格納し、次のような「ポリモーフ」操作を行うことができます。
void printValue ( Value_t value ) {
switch (value.typeValue) {
case BOOL:
printf("Bolean: %c\n", value.ParamBool?'T':'F');
break;
case ANALOG:
printf("Analog: %f\n", value.ParamAnalog);
break;
case UNKNOWN:
printf("Error, value UNKNOWN\n");
break;
}
}
最近、私は ベクトルプログラミング で使用されるいくつかの共用体を見たと思います。ベクトルプログラミングは インテルMMXテクノロジー 、GPUハードウェア、 IBMのセルブロードバンドエンジン などで使用されます。
ベクトルは128ビットのレジスタに対応します。 [〜#〜] simd [〜#〜] アーキテクチャで非常によく使用されます。ハードウェアには128ビットのレジスターがあるため、4つの単精度浮動小数点をレジスター/変数に格納できます。ベクトルの個々の要素を作成、変換、抽出する簡単な方法は、共用体を使用することです。
typedef union {
vector4f vec; // processor-specific built-in type
struct { // human-friendly access for transformations, etc
float x;
float y;
float z;
float w;
};
struct { // human-friendly access for color processing, lighting, etc
float r;
float g;
float b;
float a;
};
float arr[4]; // yet another convenience access
} Vector4f;
int main()
{
Vector4f position, normal, color;
// human-friendly access
position.x = 12.3f;
position.y = 2.f;
position.z = 3.f;
position.w = 1.f;
// computer friendly access
//some_processor_specific_operation(position.vec,normal.vec,color.vec);
return 0;
}
playStation 3マルチコアプログラミング、またはグラフィックスプログラミングの道を進んだ場合、これらの問題に直面する可能性が高くなります。
Lex
からyacc
にセマンティック値を返す場合。 (yylval
)例:
異なるソケットタイプを使用しているが、共通のタイプを参照したい場合。
ユニオンの多くの例が<X11/Xlib.h>
にあります。一部のIPスタック(BSD <netinet/ip.h>
など)にあるものはほとんどありません。
一般的なルールとして、プロトコルの実装はユニオン構造を使用します。
ユニオンは type punning の場合にも役立ちます。これは、いくつかの特定の場所( 浮動小数点比較 アルゴリズムのいくつかの手法など)で望ましいです。
もう1つの例:キャストの実行を節約する。
typedef union {
long int_v;
float float_v;
} int_float;
void foo(float v) {
int_float i;
i.float_v = v;
printf("sign=%d exp=%d fraction=%d", (i.int_v>>31)&1, ((i.int_v>>22)&0xff)-128, i.int_v&((1<<22)-1));
}
の代わりに:
void foo(float v) {
long i = *((long*)&v);
printf("sign=%d exp=%d fraction=%d", (i>>31)&1, ((i>>22)&0xff)-128, i&((1<<22)-1));
}
便宜上、共用体を使用して、同じクラスを使用してxyzw値とrgba値を格納できるようにしています
#ifndef VERTEX4DH
#define VERTEX4DH
struct Vertex4d{
union {
double x;
double r;
};
union {
double y;
double g;
};
union {
double z;
double b;
};
union {
double w;
double a;
};
Vertex4d(double x=0, double y=0,double z=0,double w=0) : x(x), y(y),z(z),w(w){}
};
#endif