2016-07-12 29 views
1
struct S1 
{ 
    char c; 
    int i; 
}; 

struct S3 
{ 
    char c1; 
    struct S1 s; 
    double c2; 
}; 

私はプログラムからそれを計算しようとしています。私は分かりませんが、S3内の構造体S1のオフセットは、このオフセットに何らかのルールがありますか?私は「S1のオフセットはそれ自身のN倍、すなわちN * sizeof(S1)」でなければならないと思ったが、それは真実ではないことがわかった。ご協力いただきありがとうございます。sizeof構造体内構造体

+1

なぜ 'offsetof(struct S3、s)'を使わないのですか? – EOF

+0

@EOF私はこの価値を得る方法を知っていますが、その原則はわかりません。コンピュータはS1のオフセットをどのように決定するのですか?ルールはありますか? – HuangJie

+0

なぜオフセットを知りたいのですか? – fukanchik

答えて

4

C標準は、これに対して意図的に柔軟です。

それは保証のすべては、(i)structの最初の要素のアドレスがstructのアドレスと同じであると、(ii)データメンバーは、それらがstructで宣言された順に表示されます。 (iii)空のstructは、非ゼロのsizeofを有する。この最後の1つは、ポインタの算術がヌル構造に対して有効であることを意味します。特に

、(任意量)パディングは任意の構造部材との間に挿入させ、最後にされています。

+0

私の実験から、S1のオフセットはsizeof(int)の時であることがわかります。ここで、intはS1の最も長い基本サイズです。 – HuangJie

+0

@ EOF:Ta。愚かな古い猫。 – Bathsheba

0

Bathshebaが述べたように、コンパイラが構造体をどのようにパッドするかは、標準によって決まりません。それは、起こっている可能性の高いことがここにあります。

特定のタイプの変数は、そのアドレスがそのタイプのサイズの倍数になるように配置する必要があります。したがって、2バイトの変数は2バイトのアドレスで開始する必要があり、4バイトの変数は4バイトのアドレスなどから開始します。structの場合、配置は最大の「ベース」タイプのものです。配列の場合は、配列全体ではなく、基本型のサイズです。

struct S1には、charと、それに続くintがあります。 intが4バイトであるとすると、それはciの間に3バイトのパディングが必要であることを意味します。だから、暗黙のパディングを持つ構造体は次のようになります。

struct S1 
{ 
    char c;    // offset 0 
    char padding[3];  // offset 1 
    int i;    // offset 4 
}; 

これは私たちsizeof(struct S1) == 8を与えます。

struct S3には、struct S1というインスタンスがありますが、これは8バイト(ただし4バイトのアライメントがあります)とdoubleで、おそらく8バイトです。したがって、それらが正しく整列されるためには、c1の後に3バイトのパディングが必要であり、次にsの後に4つのパディングが必要です。だから今、暗黙のパディングとstruct S3は次のようになります。

struct S3 
{ 
    char c1;   // offset 0 
    char padding[3]; // offset 1 
    struct S1 s;  // offset 4 
    char padding[4]; // offset 12 
    double c2;   // offset 16 
}; 

私たちは、その後、sizeof(struct S3) == 24を持っています。

このようなパディングスキームは、あなたが遭遇する可能性が最も高いものですが、この規格では保証されません。

+1

'struct S3'のレイアウトに関するあなたの前提は間違っている可能性があります。 'struct S1'は' sizeof(int) '境界に整列するだけでよいので、' struct S3'の 'char c1'の後ろには3バイトのパディングしかないでしょう。 'double SI2'は' sizeof(double) 'に整列されなければならないので、残りのパディングは' struct S1 s'の後にあります。 – EOF

+0

@EOFそうです、それはフルサイズで 'struct'を整列させるよりも理にかなっています。反映するように編集。 – dbush

+0

アラインメント「必要性」についての注意。典型的なデフォルトのパディングは、最小のデータ間隔ではなく効率的なコードを促進するために行われます。 – chux

1

Cの標準(〜2011)は、これをほとんど不特定にしています。 2011年の標準でこれが変更されました。

原則として、すべてのデータ型は、その型のオブジェクトが割り当てられる(または格納される)連続したアドレス間のバイト数で表される整列要件があります。

structタイプのアドレスも、最初のメンバー(2011年以降ではなく、すべてのC標準)のアドレスと同じです。この結果、2011年から、structタイプのアラインメントは、最初のメンバーのアライメントの倍数になります。

structのすべてのメンバーは、最初のメンバーだけでなく、そのタイプに基づいたアラインメントも持っている必要があります。たとえば、intメンバーのアライメント要件はintdoubleメンバーのアライメント要件はdouble、アレイのアライメント要件はアレーのサイズ(要素数倍、sizeof要素の数)になります。

最も弱い位置合わせ(アライメント最小要件)が1に等しいcharsigned char、及びunsigned charのアラインメントです。当然のことながら、より大きな型はより大きな整列の必要性を持っています。

実際に実装すると、structのすべてのメンバーが独自のアライメント要件を満たすように、必要に応じて埋め込みが追加されます。

以上は単純化されていますが、タイプとオブジェクトの配置方法に影響を与えるalignasのような、2011年標準に導入されたその他の機能はありません。

0

これは、構造体内のパディングが原因です。コンピュータは変数を任意のアドレスに格納せず、変数を4バイトの倍数に格納しようとします。変数に収まらない場合は、次の複数の4バイトの後に変数を設定します。

Address | Variable 
--------|--------- 
1000 | char c 
1001 | char d 
1002 |    //Empty so that the next int can occupy 
1003 |    // 4 bytes 
1004 | int x  
1005 | - 
1006 | -  //Filled till 1007 so next variable can 
1007 | -  // start from 1008 
1008 |  
1009 | 

Cプロセッサは構造体と同じ規則に従い、領域を残して変数を4バイトのスペースに収めようとします。

The Lost art of Struct packingを参照してください。

+0

このリンクは質問に答えるかもしれませんが、回答の重要な部分をここに含めて参考にしてください。リンクされたページが変更された場合、リンクのみの回答は無効になります。 - [レビューから](/レビュー/低品質の投稿/ 16815714) – McGrady

+0

すみません。私はそれを編集します、私はstackoverflowに新しいです..:/ –