2016-08-19 11 views
1

を格納するコードである:連合はここで複数の値

#include <iostream> 

union mytypes_t { 
    char c; 
    int i; 
    float f; 
    double d; 
} mytypes; 

int main() { 

    mytypes.c = 'z'; 
    mytypes.d = 4.13021; 
    mytypes.f = 41.7341; 

    cout << mytypes.d << endl; 
    return 0; 
} 

プログラム出力4.13021は、(値がdoubleとして宣言)。代わりにmytypes.cを出力しようとすると、(文字が正しく表示されていないことを示す)空白の四角が印刷されます。

私が組合について理解していることから、単一の値の単一の値を保持してはいけませんか?それが本当であれば、値41.7341の浮動小数点数にはならないでしょうから、doubleまたはcharとして呼び出すとエラーになりますか?

+5

"これはC++です。 :)未定義の動作が発生します。 – GManNickG

+1

ユニオンのアクティブでない部分にアクセスすることは、未定義の動作であることに注意してください。 – NathanOliver

+0

エラーが必要な場合は、 'boost :: variant'のようなバリアント型を使用してください。 – chris

答えて

1

他の回答に記載されているように、すべてのユニオンメンバーは同じメモリスペースを占有します。メモリは常にベースタイプとして解釈できますが、結果は予期しないことがあります。

私は16進数でいくつかの詳細を印刷するコードを作成しました。連続した値が割り当てられるたびにメモリが変化することがわかります。浮動小数点数が割り当てられたときに倍精度浮動小数点値が完全に変更されないため、出力値は元の値に近くなります。これは、タイプ・サイズとハードウェア・アーキテクチャーの副作用に過ぎません。

なぜなら、coutを使用して16進文字を印刷するのはそんなに苦しいことです。

#include <iomanip> 
#include <iostream> 
#include <string.h> 

union mytypes_t { 
    unsigned char a[8]; 
    char c; 
    int i; 
    float f; 
    double d; 
} mytypes; 

int main() { 

    memset(&mytypes,0,8); 

    std::cout << "Size of the union is: " << sizeof(mytypes) << std::endl; 
    mytypes.c = 'z'; 
    for(int i=0;i<8;i++) 
     printf("%02x ", mytypes.a[i]); 
    printf("\n"); 

    mytypes.d = 4.13021; 
    for(int i=0;i<8;i++) 
     printf("%02x ", mytypes.a[i]); 
    printf("\n"); 

    mytypes.f = 41.7341; 
    for(int i=0;i<8;i++) 
     printf("%02x ",mytypes.a[i]); 
    printf("\n"); 

    std::cout << mytypes.c << std::endl; 
    std::cout << mytypes.d << std::endl; 
    std::cout << mytypes.f << std::endl; 
    return 0; 
} 


Size of the union is: 8 
7a 00 00 00 00 00 00 00 // The char is one byte 
da 72 2e c5 55 85 10 40 // The double is eight bytes 
b8 ef 26 42 55 85 10 40 // The float is the left most four bytes 
� 
4.13021 
41.7341 
0

ユニオンの目的は、同じメモリ領域に多くの型を割り当てることです。したがって、共用体にはメモリーがあり、その共用体で宣言したタイプに基づいてそのメモリーを表すことができます。

charを明示的にdouble型にキャストするか、またはその逆の型を明示的にキャストすると、エラーが発生します。共用体は基本的に型キャスティングであり、メモリーは使用されません。

+0

明示的なキャストは変換を実行します。組合はそうしない。 –

0

私はあなたのタイプについていくつかの仮定をして、この説明のための具体的な数字を持っています。私は仮定:char = 1バイト、intとfloat = 4バイト、倍精度= 8バイト。

ここで、それらはメモリ内の同じ場所に保存されます。通常、構造体にintとfloatを宣言すると、intは最初の4バイトを占め、floatは2番目の4バイトを占有します。しかし、保存されるデータはすべて0と1であり、intやfloatと同じ数を保存すると、システムによって異なる解釈が行われるため、0と1の順序が異なります。たとえば、int,float

あなたの組合のフィールドの1つに保存すると、指定したものに対応する0と1の正しい順序が取られ、そこに格納されます。 intフィールドに15を保存してフロートとして読み込んだ場合、意図した順序とは異なる順序で数値を読み込まなければならないため、完全に異なる数値を取得します。

これはすべて@GManNickGがコメントで言ったことになります。これは未定義の動作です。 0と1のシーケンスはまだ数字であり、あなたが思うものではありません。それを数字で読んでそれを使って計算するのは完全に有効です。そのため、通常、共用体を使用するものは、共用体とは別に定義された2番目のフィールド(しばしば列挙型)を持っているので、プログラムの別の部分が後で使用するときにどの型を読み込むかを知ることができます。

関連する問題