2016-10-24 9 views
-2

組み込みプログラミングでは、時には15組の構造体を1つの共用体に配置することがよくあります。それは一般的な習慣であり、私を含む私はそれがRAMが小さすぎると貴重すぎるので、スペースを節約するためだと仮定することを含むほとんどの人。しかし、今私は疑問に思っています、他の考慮事項はありますか?たとえば、スピードは?スペースを節約できるだけでなく、ユニオンを使用する他の特長もありますか?

啓発してお知らせください。ここで

があなたの思考のための一例の食べ物です:

typedef struct 
{ 
union 
{ 
    struct{ 
    ... 
    } stru1; 


    struct{ 
    ... 
    } stru2; 


    struct{ 
    ... 
    } stru3; 


    struct{ 
    ... 
    } stru4; 

} 
}main_packet 
+1

あなたはそれがスペースを節約すると思いますどのように?これは、仕様で定義されているまったく別の理由であり、おそらくチュートリアルや書籍Cを説明しています。 –

+1

'ユニオン 'はその最大のアイテムのサイズをとります。逆の場合は:たくさんのスペースを無駄にします。 – LPs

答えて

4

、それはバリアントを作成するためにそれを使用している「スペースを節約」するために労働組合を使用して、通常は悪い習慣と考えられている(例えばMISRAによって禁止-C)、私は何も勧めません。バリアント型の存在は、ほとんど常に悪いプログラム設計の兆候です。

ユニオンの最も一般的な目的は、型のパニングでそれを使用することです。つまり、1つのユニオンメンバーに書き込み、別のメンバーからそのデータを読み取ることができます。これはC言語でよく定義された動作であり、ハードウェア関連のプログラミングを行うときには非常に便利です。

は、たとえば、あなたがこのような何かを行うことができます。

typedef union 
{ 
    uint32_t u32; 
    uint8_t u8 [4]; 
} my32_t; 

my32_t my32; 
my32.u32 = 1; 

if(my32.u8[0] == 1) 
{ 
    puts("little endian"); 
} 
else 
{ 
    puts("big endian"); 
} 

組合もかわすthe strict aliasing rulesに使用することができます。このようなコードは未定義の動作を呼び出します:

typedef union 
{ 
    uint32_t u32; 
    uint16_t u16; 
} something_t; 

something_t x; 
x.u32 = 1; 
uint16_t u16 = x.u16; 

これは、6.5に記載されている厳格なエイリアシングから例外ごとなど、明確に定義された動作です:

uint32_t u32 = 1; 
uint16_t u16 = *(uint16_t*)&u32; // bad, strict aliasing violation 

このバグを回避するために、コードは以下のように書き換えることができます/ 7:

  • 再帰的に含むそのメンバー(うち、前述のタイプのいずれか、0のメンバーを含む集合体または共用タイプsubaggregateまたは含ま組合)
+0

申し訳ありません迷惑をかける最後の例はエンディアンに依存しますね。私は 'u16'は' 0'になることを意味します。 – LPs

+0

@LPはい、あります。そのため、ほとんどの場合、整数型の特定の部分にシフトを介してアクセスするほうがよいでしょう。しかし、私はあなたがu16チャンクでu32​​を読んでみたいという本当のシナリオがあると思います。たとえば、私は16ビットしかプログラムできないeepromドライバを書くことを覚えています。 – Lundin

+0

はい、私は 'uint16_t u16 [sizeof(uint32_t)/ sizeof(uint16_t)];を使って何度もやりました。 – LPs

0

動的なメモリ割り当て(malloc関数/無料)が重複しないデータ構造whoses寿命のためにメモリを再利用することで、スペースを節約するための一般的な方法です。組合は、この目的のために非常に柔軟性がなく、維持しがたいアプローチです。これらは、malloc/freeの時間オーバーヘッドが本当に受け入れられないような異常な場合にのみ使用してください。

共用体は、C++でコーディングしていた場合、クラス階層となる「原始的な」ビーストを提供するためにも使用されます。代わりに:

class A { ... }; 
class B : public A { ... }; 
class C : public A { ... }; 
class D : public A { ... }; 

あなたが書く:あなたがCでB、C、Dのために必要な異なる動作を取得するために仮想関数を使用するC++では

struct H 
    { 
    struct A a; 
    enum { Really_B, Really_C, Really_D } really; 
    union 
     { 
     struct B b; 
     struct C c; 
     struct D d; 
     }; 
    }; 

、あなたはそれほど保守性スイッチまたは/場合を使用しますそうでなければ、 "派生型"識別子フィールド(この場合は "本当に")を使用して構築します。

組合ではなく、ポインタのもを使用することができ、異なるタイプとして生のバイトを解釈するためにキャスト:

typedef union 
    { 
    float fp; 
    struct 
     { 
     unsigned fraction : 23; 
     unsigned exponent : 8; 
     unsigned sign  : 1; 
     } 
    fld; 
    } 
Floating_point; 
関連する問題