20

コードフラグメントのみを実行すると

int *t;
std::cout << sizeof(char)   << std::endl;
std::cout << sizeof(double) << std::endl;
std::cout << sizeof(int)    << std::endl;
std::cout << sizeof(t)      << std::endl;

次のような結果が得られます。

1
8
4
4

合計:17。

しかし、これらのデータ型を含むsizeof structをテストすると、24が得られ、混乱します。追加の7バイトは何ですか?

これはコードです

#include <iostream>
#include <stdio.h>
struct struct_type{
    int i;
    char ch;
    int *p;
    double d;
} s;

int main(){
    int *t;
    //std::cout << sizeof(char)   <<std::endl;
    //std::cout << sizeof(double) <<std::endl;
    //std::cout << sizeof(int)    <<std::endl;
    //std::cout << sizeof(t)      <<std::endl;

    printf("s_type is %d byes long",sizeof(struct struct_type));

    return 0;
}

:編集

このようにコードを更新しました

#include <iostream>
#include <stdio.h>
struct struct_type{
    double d_attribute;
    int i__attribute__(int(packed));
    int * p__attribute_(int(packed));;
    char  ch;
} s;

int main(){
    int *t;
    //std::cout<<sizeof(char)<<std::endl;
    //std::cout<<sizeof(double)<<std::endl;
    //std::cout<<sizeof(int)<<std::endl;
    //std::cout<<sizeof(t)<<std::endl;

    printf("s_type is %d bytes long",sizeof(s));

    return 0;
}

そして今それは私に16バイトを示しています。それは良いですか、それとも私はいくつかの重要なバイトを失いましたか?

4

9 に答える 9

52

アライメントを正しく保つために、一部のメンバー間に未使用のバイトがいくつかあります。たとえば、ポインタはデフォルトで効率を上げるために4バイト境界にあります。つまり、そのアドレスは4の倍数である必要があります。構造体にcharとポインタのみが含まれている場合

struct {
  char a;
  void* b;
};

そのb場合、加算器#1を使用できません—#4に配置する必要があります。

  0   1   2   3   4   5   6   7
+---+- - - - - -+---------------+
| a | (unused)  | b             |
+---+- - - - - -+---------------+

あなたの場合、余分な7バイトは、のアラインメントによる3バイトと、のアラインメントint*による4バイトから来ていますdouble

  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+---------------+---+- - - - - -+---------------+- - - - - - - -+
| i             |ch |           | p             |               |
+---------------+---+- - - - - -+---------------+- - - - - - - -+
 10  11  12  13  14  15  16  17
+-------------------------------+
| d                             |
+-------------------------------+
于 2010-08-15T09:39:45.547 に答える
9

...それは私に24を与えます、そして私は混乱しています。追加の7バイトは何ですか?

これらは、コンパイラによって挿入されたパディングバイトです。データ構造のパディングは実装に依存します。

ウィキペディアから、データ構造のアライメント

データアライメントとは、ワードサイズの倍数に等しいメモリオフセットにデータを配置することを意味します。これにより、CPUがメモリを処理する方法により、システムのパフォーマンスが向上します。データを整列させるには、最後のデータ構造の終わりと次のデータ構造の始まりの間に意味のないバイトを挿入する必要がある場合があります。これはデータ構造のパディングです。

于 2010-08-15T09:37:08.733 に答える
8

KennyDMの優れた答えを少し拡張するために(Kenny-必要に応じて答えを補足するためにこれを盗んでください)、コンパイラがすべての変数を整列させた後のメモリ構造はおそらく次のようになります。

  0    1    2    3    4    5    6    7
+-------------------+----+-----------+
| i                 | ch | (unused)  |
+-------------------+----+-----------+

  8    9   10   11   12   13   14   15
+-------------------+----------------+
| p                 |   (unused)     |
+-------------------+----------------+

 16   17   18   19   20   21   22   23
+------------------------------------+
| d                                  |
+------------------------------------+

したがって、「ch」と「p」の間に3バイトのギャップがあり、「p」と「d」の間に4バイトのギャップがあるため、構造体に7バイトのパディングがあり、サイズは24バイトになります。ご使用の環境doubleには8バイトのアラインメントがあるため(つまり、上記のように、環境は8バイトの独自のブロックに存在する必要があります)、全体structも8バイトにアラインされ、変数の順序を変更することもできます。サイズを24バイトから変更しません。

于 2010-08-15T09:58:27.230 に答える
1

パディングのために24バイトです。ほとんどのコンパイラは、データをそのサイズの倍数にパディングします。したがって、4バイトのintは4バイトの倍数にパディングされます。8バイトのdoubleは、8バイトの倍数にパディングされます。あなたの構造にとって、これは次のことを意味します:

struct struct_type{
  int i; // offset 0 (0*4)
  char ch; // offset 4 (4*1)
  char padding1[3];
  int *p; // offset 8 (2*4)
  char padding1[4];
  double d; // offset 16 (2*8)
}s;

次のように構造体を最適化できます。

struct struct_type{
  double d;
  int i;
  int *p;
  char ch;
}s;

sizeof(s)==ほとんどのコンパイラで17(他の一部のコンパイラでは20)

于 2010-08-15T09:48:03.467 に答える
0

コンパイラーは、より高速なアクセスのために、構造体のメンバーをアドレスに整列させることができます。例:32ビット境界。オブジェクトのメンバーが宣言された順序で格納されることは、標準によってのみ要求されます。したがって、メモリ内の正確な位置が必要な場合は、必ず使用してくださいsizeofoffsetof

于 2010-08-15T09:39:59.130 に答える
0

comp.lang.c FAQリストを参照してください・質問2.12 :

コンパイラが構造に穴を残し、スペースを浪費し、外部データファイルへの「バイナリ」I / Oを防止するのはなぜですか?これをオフにすることはできますか、それとも構造フィールドの配置を制御できますか?

于 2010-08-15T09:43:20.850 に答える
0

追加のサイズはデータアライメントから生じます。つまり、メンバーは4バイトまたは8バイトの倍数にアライメントされます。

コンパイラはおそらく、intとポインタを4バイトの場合は倍数に、doubleを8バイトの場合は倍数にアラインします。

構造体内の別の位置にdoubleを移動すると、構造体のサイズを24バイトから20バイトに減らすことができる場合があります。しかし、それはコンパイラに依存します。

于 2010-08-15T09:44:49.353 に答える
0

また、必要な順序を維持するための構造体が必要になる場合もあります。この場合、gccを使用している場合は、__attribute__((packed))ステートメントを使用する必要があります。

詳細については、こちらもご覧ください。

于 2010-08-15T09:45:28.510 に答える
0

$ 9.2 / 12の状態-「アクセス指定子が介在せずに宣言された(非ユニオン)クラスの非静的データメンバーは、後のメンバーがクラスオブジェクト内でより高いアドレスを持つように割り当てられます。アクセスによって分離された非静的データメンバーの割り当て順序-指定子が指定されていません(11.1)。実装のアライメント要件により、隣接する2つのメンバーがすぐに割り当てられない場合があります。したがって、仮想関数(10.3)および仮想基本クラス(10.1)を管理するためのスペースの要件があります。」

したがって、sizeof(double)およびsizeof(int)と同様に、後で宣言されるメンバーがより高いアドレスにあることを除いて、構造体メンバーが整列されるオフセットは指定されていません。

于 2010-08-15T09:54:05.663 に答える