2017-12-08 16 views
7

私は構造体Baseから継承する構造体Xを持っています。アライメントに、Xのサイズは24Bですが、私の現在の設定では、:アンワインドによる継承は厳密なエイリアシングルールに違反していますか?

typedef struct { 
    double_t a; 
    int8_t b; 
} Base; 

typedef struct { 
    Base base; 
    int8_t c; 
} X; 

メモリを節約するために、私は、基本構造体をほどくしたいと思いますので、私はからフィールドを含む構造体Yを作成しましたベース(同じ順序で、常に構造体の先頭)、構造体のサイズは16Bですので:

typedef struct { 
    double_t base_a; 
    int8_t base_b; 
    int8_t c; 
} Y; 

その後、私はポインタを期待する方法で構造体Yのインスタンスを使用するつもりですベース構造体:

void print_base(Base* b) 
{ 
    printf("%f %d\n", b->a, b->b); 
} 
// ... 
Y data; 
print_base((Base*)&data); 

上記のコードは厳密なエイリアシング規則に違反し、未定義の動作を引き起こしますか?

+0

右は、なぜあなたは、単に基本ベース'宣言しないコード例 –

+0

を固定します); '?他の構造体のstructのメンバと同じメモリを消費します。 – mch

+1

@mchはありません。あなたのアプローチを使用する構造体Xのサイズは24バイトをとりますが、構造体Yのみ16 –

答えて

8

まず、BaseYは、標準6.2.7で定義されている互換性のあるタイプではありません。すべてのメンバーが一致しなければなりません。 「集約型」であることが必要Y厳密エイリアシング違反を作成せずにBase*スルーYにアクセスする

(それは)そのメンバー間Baseタイプを含みます。それはしません。

したがって、厳密なエイリアシング違反です。さらに、YBaseは互換性がないため、異なるメモリレイアウトを持つ可能性があります。どのような全体のポイントの種類は、非常に理由の異なるタイプを作った:)

これは、共通の初期シーケンスを共有する構造体メンバーとの結合を使用することです。特別な許された場合。 C11 6.5.2.3からの有効なコードの例:;(&data.base Y` `で`とprint_base `で関数を呼び出す

union { 
    struct { 
    int alltypes; 
    } n; 
    struct { 
    int type; 
    int intnode; 
    } ni; 
    struct { 
    int type; 
    double doublenode; 
    } nf; 
} u; 

u.nf.type = 1; 
u.nf.doublenode = 3.14; 
/* ... */ 
if (u.n.alltypes == 1) 
    if (sin(u.nf.doublenode) == 0.0) 
+0

ありがとうございます。私はメモリのレイアウトについては分かりません。最初の2つのフィールド(Baseのa、b、base_a、Yのbase_b)のオフセットが同じであるという標準的な保証はありませんか? –

+1

@MarcinKolnyこれはメモリのレイアウトに関するものではありません。メモリのレイアウトは、両方のタイプで同じです。これはコンパイラオプティマイザに知らせることです。あなたは 'union {Base b; y y;}; 'という値をヘッダーに入れ、' y.base_a 'の値が変更されたときにいつでもメモリから値' b.a 'をリロードする必要があることをオプティマイザに通知します。 – Marian

+0

@マリアンのおかげで、それは興味深いと思う。好奇心が強い、あなたが私がこれについてもっと読むことができるいくつかの記事を指摘することができますか? –

関連する問題