2016-10-14 9 views
2

サンプルコード:構造体のパディングバイトはメンバの割り当てによって保持されますか?

#include <assert.h> 

struct S 
{ 
    unsigned char ch; 
    int i; 
}; 

int main() 
{ 
    struct S s; 

    memset(&s, 0, sizeof s); 

    s.ch = 257; 

    assert(0 == ((unsigned char *)&s)[1]); 
} 

アサーションが失敗することはできますか?

質問の動機はリトルエンディアンシステム上のコンパイラがs.ch = 257;を実装するために4バイトのストアを使用することを決定することができるかどうかです。私は私の例で行ったように明らかに誰もがこれまでのコードを記述しないだろうが、chはその後、構造体の等価性をチェックするためにmemcmpを使用するために行くのプログラムでは、さまざまな方法で割り当てられている場合と同様のものが現実的に発生する可能性があります。

例えば、コードがs.ch = 257の代わりに--s.chの場合、コンパイラはワードサイズ減少命令を発行できますか?

私は初期化されていないパディングに適用されるようDR 451周りの議論は、関連性があるとは思いません。 memsetはすべてのパディングを0バイトに初期化します。

答えて

0

ISO/IEC 9899:2011§6.2.6.1(タイプの表現)一般は言う:

¶6値をメンバに含む、構造体または共用型のオブジェクトに格納されている場合任意のパディングバイトに対応するオブジェクト表現のバイトは、不特定の値をとる。 51)構造体または共用体オブジェクトのメンバの値がトラップ表現であっても、構造体または共用体オブジェクトの値は決してトラップ表現ではありません。

51)たとえば、構造体の割り当てでは、パディングビットをコピーする必要はありません。

しかし、あなたの例では構造体割り当てが行われないため、適用されない可能性があります。私は、構造体の単純な型メンバーへの代入がデータを変更すると考える理由がないと信じています。

しかし、あなたのassertコードは単純に許可されていない構造のパディングを、アクセスしようと、未定義の挙動を示すん。

だから、アサーションが火とは考えにくいですが、あなたのコードは未定義の挙動を示すので、それが起こる可能性があり、あなたは何の頼みの綱を持っていないと思います。

+0

あなたの見積もりに「メンバーオブジェクトに含める」が見落とされました。私の質問に答えるようです。しかし、なぜ構造体のパディング(初期化されていない)にアクセスするのが未定義の動作になるのかわかりません。 –

+0

これは未定義の動作である「アクセスパディング」です。その初期化ステータスはアクセスできないため、無関係です。しかし、標準の関連部分を見つけるのに私はしばらく時間がかかるかもしれません... –

+0

メモをつくる - これは私の答えの最終的な追加の一部かもしれません:§7.14.4.1** 'memcmp'関数** memcmp関数は、s1が指すオブジェクトの最初のn個の文字と、 とを比較します(s2.310で指し示されるオブジェクトの最初のn文字)。 - 310)構造内の整列のためにパディングとして使用される「穴」の内容オブジェクトは 不確定です。割り当てられた領域および共用体より短い文字列は、 比較でも問題を引き起こす可能性があります。 –

3

はい、失敗する可能性があります。この動作は未定義ですが、未定義ではありません。

割り当てs.ch = 257;後、すべてのパディングビットの値は、構造の第2バイトはパディングバイトである場合、それは不特定の値とゼロとの比較の結果を取る、つまり、不特定の値をとるが、指定されていません。それは誘発してもしなくてもよい。

unsigned char型トラップ表現を持っていないため、アサートの読み出し値は、トラップ表現することができず、値は不定、不特定ではないからです。 ISO/IEC 9899:201X 6.2.6


は(より引用します。1一般6):
値がオブジェクト オブジェクトを含む構造体または共用体型のオブジェクトに格納される場合、任意のパディング・バイトに対応するオブジェクト表現のバイトは、 の不特定の値をとります。

関連する問題