sizeof(struct)の結果分析とその原因
4584 ワード
sizeofは面接でよく受ける知識点で、今私はネット上から1篇の文章を転載してとてもすばらしくて、参考にすることができます!
転載先:http://blog.csdn.net/xinjixjz/article/details/6769344
ある時、頭の中で長い間立ち止まっていた「明らか」なものは、実は根本的に間違っていた.struct T{char ch;int i;};sizeof(T)を使うと、どのような答えが得られますか?以前なら考えなくても32ビットマシンでintは4バイト、charは1バイトなのでTは全部で5バイトです.実際には、VC 6でテストしたところ、答えは確かに8バイトでした.ああ、どうせ怪我をしたのはいつも私で、私はもう少ししびれて、やはり正直に受け入れましょう!どうして答えは自分が想像していたものと違うのでしょうか.ここでは、メモリの位置合わせという概念を導入します.
二メモリ整列の概念とその提案の原因
多くのコンピュータシステムでは、内蔵タイプの格納場所に一定の制限があり、通常、対応するタイプが一定の倍数kで格納され、メモリの位置合わせとなります.ここで、kはメモリモジュール数と呼ばれる.
DEF:sizeof(struct S 1)/sizeof(struct S 2)>1の場合、S 1の位置合わせはS 2の位置合わせよりも厳密であり、逆である.
なぜメモリの位置合わせを提案しますか?
例えば、メモリを読み書きするたびに8倍のアドレスから始まり、8バイトのデータを一度に読み書きします.doubleタイプのデータが8倍のアドレスから始まることを保証できれば、doubleタイプのデータを読み書きするには1回のメモリ操作しか必要ありません.そうでなければ、データが2つの整列要件を満たす8バイトのメモリブロックにまたがっている可能性があるため、この動作を完了するには2回のメモリ操作が必要になる可能性があります.(有謝プロセッサでメモリが揃わないとエラーが発生する可能性があります)
いくつかの例(vcのコンパイラで)
以下では,VCがどのように構造を格納するかを前の例で説明する.
struct MyStruct
{
double dda1;
char dda;
int type
};
上記の構造に空間を割り当てる場合、VCは、メンバー変数が現れる順序と位置合わせに応じて、まず最初のメンバーdda 1に空間を割り当て、その開始アドレスは構造の開始アドレスと同じ(ちょうどオフセット量0はsizeof(double)の倍数)であり、このメンバー変数はsizeof(double)=8バイトを占有する.次に、2番目のメンバddaに空間を割り当てる.このとき、次に割り当てることができるアドレスは、構造の先頭アドレスに対するオフセット量が8であり、sizeof(char)の倍数であるため、オフセット量が8の場所にddaを格納し、sizeof(char)=1バイトを占有する整列方式を満たす.次に3番目のメンバtypeに空間を割り当てるが、このとき次に割り当てることができるアドレスの構造の先頭アドレスに対するオフセット量は9でsizeof(int)=4の倍数ではなく、位置合わせ方式のオフセット量に対する制約問題を満たすために、VCは3バイト(この3バイトには何も入っていない)を自動的に充填し、この場合、次の割り当て可能なアドレスの構造の開始アドレスに対するオフセット量は12であり、ちょうどsizeof(int)=4の倍数であるため、typeはオフセット量が12の場所に格納され、このメンバー変数はsizeof(int)=4バイトを占有する.このとき、構造全体のメンバー変数にはすでに空間が割り当てられており、総占有空間の大きさは:8+1+3+4=16であり、ちょうど構造のバイト境界数(すなわち、構造内で最大空間を占有するタイプが占有するバイト数sizeof(double)=8)の倍数であるため、空きのないバイトは充填する必要がある.したがって,構造全体の大きさはsizeof(MyStruct)=8+1+3+4=16であり,そのうち3バイトがVCで自動的に埋め込まれ,意味のあるものは何も置かれていない.
例を挙げて、上のMyStructのメンバー変数の位置を交換して、次のようにします.
struct MyStruct
{
char dda;
double dda1;
int type
};
この構造が占有する空間はどのくらいですか?VC 6.0環境では、sizeof(MyStruc)が24であることが得られる.上述した分配空間のいくつかの原則を結びつけて、VCがどのように上の構造のために空間を分配するかを分析します.(簡単な説明)
struct MyStruct
{
};//すべてのメンバー変数にはスペースが割り当てられています.スペースの合計サイズは1+7+8+4=20で、構造ではありません.
//のセクション境界数(すなわち、構造内で最大空間を占有するタイプが占有するバイト数sizeof
//(double)=8)の倍数なので、構造の大きさが
//sizeof(double)=8の倍数です.
従って、この構造の総サイズは、sizeof(MyStruc)が1+7+8+4+4=24である.このうち総7+4=11バイトはVCで自動的に埋め込まれ、意味のあるものは何も入っていません.
VCの構造に対する記憶の特殊な処理は確かにCPUが変数を記憶する速度を高めて、しかし時にはいくつか面倒をもたらして、私達も変数のデフォルトの位置合わせの方式を遮断して、自分で変数の位置合わせの方式を設定することができます.
VCには、変数をnバイトで整列するように設定するためのpragma pack(n)が設けられている.nバイトアライメントとは、変数が格納される先頭アドレスのオフセット量の2つのケースがある.第1に、nが変数が占有するバイト数以上である場合、オフセット量はデフォルトのアライメント方式を満たさなければならない.第2に、nが変数のタイプが占有するバイト数未満である場合、オフセット量はnの倍数であり、デフォルトのアライメント方式を満たさない.構造の合計サイズにも制約があり、nがすべてのメンバー変数タイプが占有するバイト数より大きい場合、構造の合計サイズは、占有空間が最大の変数が占有する空間数の倍数でなければならない.
そうでなければnの倍数でなければなりません.次に、その使い方を例に挙げて説明します.
pragma pack(push)/位置合わせ状態の保存
pragma pack(4)/4バイト揃えに設定
struct test
{
char m1;
double m4;
int m3;
};
pragma pack(pop)/位置合わせ状態の回復
以上の構成の大きさは16であり、以下ではその記憶状況を分析し、まずm 1に空間を割り当て、そのオフセット量は0であり、私たちが設定した位置合わせ方式(4バイト位置合わせ)を満たし、m 1は1バイトを占有する.次にm 4に空間を割り当て始めると、そのオフセット量は1であり、オフセット量がn=4の倍数(sizeof(double)がnより大きいため)を満たすように3バイト補完する必要があり、m 4は8バイトを占有する.次にm 3に空間を割り当てると,そのオフセット量は12であり,4の倍数を満たし,m 3は4バイトを占有する.このとき,すべてのメンバ変数に空間が割り当てられ,nの倍数を満たす16バイトが割り当てられた.上記の#pragma pack(4)を#pragma pack(16)に変更すると、構造の大きさは24となる.(読者自身で分析してください)
2、sizeof用法まとめ
VCではsizeofには多くの使い方があり、いくつかのエラーを引き起こしやすい.次にsizeofの後のパラメータに基づいてsizeofの使い方をまとめます.
A.パラメータはデータ型または一般変数です.たとえばsizeof(int)、sizeof(long)などです.この場合、異なるシステムシステムまたは異なるコンパイラで得られた結果は異なる可能性があることに注意してください.例えばintタイプは16ビットシステムで2バイト,32ビットシステムで4バイトである.
B.パラメータは配列またはポインタである.以下、例を挙げる説明する.
int a[50];//sizeof(a)=4*50=200;配列の占める空間の大きさを求めます
int *a=new int[50];//sizeof(a)=4; aは1つのポインタであり、sizeof(a)はポインタを求める
//のサイズは、32ビットシステムでは、もちろん4バイトです.
C.パラメータは構造またはクラスである.Sizeofがクラスや構造に適用される処理は同じである.しかし、静的変数の格納位置は、構造またはクラスのインスタンスアドレスとは無関係であるため、第1、構造またはクラスの静的メンバーは、構造またはクラスのサイズに影響を及ぼさない点に注意してください.
第二に、メンバー変数のない構造またはクラスのサイズは1であり、構造またはクラスの各
個のインスタンスには、メモリに一意のアドレスがあります.
次に例を挙げて説明します.
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,sはポインタです.
Class test1{ };//sizeof(test1)=1;
転載先:http://blog.csdn.net/xinjixjz/article/details/6769344
ある時、頭の中で長い間立ち止まっていた「明らか」なものは、実は根本的に間違っていた.struct T{char ch;int i;};sizeof(T)を使うと、どのような答えが得られますか?以前なら考えなくても32ビットマシンでintは4バイト、charは1バイトなのでTは全部で5バイトです.実際には、VC 6でテストしたところ、答えは確かに8バイトでした.ああ、どうせ怪我をしたのはいつも私で、私はもう少ししびれて、やはり正直に受け入れましょう!どうして答えは自分が想像していたものと違うのでしょうか.ここでは、メモリの位置合わせという概念を導入します.
二メモリ整列の概念とその提案の原因
多くのコンピュータシステムでは、内蔵タイプの格納場所に一定の制限があり、通常、対応するタイプが一定の倍数kで格納され、メモリの位置合わせとなります.ここで、kはメモリモジュール数と呼ばれる.
DEF:sizeof(struct S 1)/sizeof(struct S 2)>1の場合、S 1の位置合わせはS 2の位置合わせよりも厳密であり、逆である.
なぜメモリの位置合わせを提案しますか?
例えば、メモリを読み書きするたびに8倍のアドレスから始まり、8バイトのデータを一度に読み書きします.doubleタイプのデータが8倍のアドレスから始まることを保証できれば、doubleタイプのデータを読み書きするには1回のメモリ操作しか必要ありません.そうでなければ、データが2つの整列要件を満たす8バイトのメモリブロックにまたがっている可能性があるため、この動作を完了するには2回のメモリ操作が必要になる可能性があります.(有謝プロセッサでメモリが揃わないとエラーが発生する可能性があります)
いくつかの例(vcのコンパイラで)
以下では,VCがどのように構造を格納するかを前の例で説明する.
struct MyStruct
{
double dda1;
char dda;
int type
};
上記の構造に空間を割り当てる場合、VCは、メンバー変数が現れる順序と位置合わせに応じて、まず最初のメンバーdda 1に空間を割り当て、その開始アドレスは構造の開始アドレスと同じ(ちょうどオフセット量0はsizeof(double)の倍数)であり、このメンバー変数はsizeof(double)=8バイトを占有する.次に、2番目のメンバddaに空間を割り当てる.このとき、次に割り当てることができるアドレスは、構造の先頭アドレスに対するオフセット量が8であり、sizeof(char)の倍数であるため、オフセット量が8の場所にddaを格納し、sizeof(char)=1バイトを占有する整列方式を満たす.次に3番目のメンバtypeに空間を割り当てるが、このとき次に割り当てることができるアドレスの構造の先頭アドレスに対するオフセット量は9でsizeof(int)=4の倍数ではなく、位置合わせ方式のオフセット量に対する制約問題を満たすために、VCは3バイト(この3バイトには何も入っていない)を自動的に充填し、この場合、次の割り当て可能なアドレスの構造の開始アドレスに対するオフセット量は12であり、ちょうどsizeof(int)=4の倍数であるため、typeはオフセット量が12の場所に格納され、このメンバー変数はsizeof(int)=4バイトを占有する.このとき、構造全体のメンバー変数にはすでに空間が割り当てられており、総占有空間の大きさは:8+1+3+4=16であり、ちょうど構造のバイト境界数(すなわち、構造内で最大空間を占有するタイプが占有するバイト数sizeof(double)=8)の倍数であるため、空きのないバイトは充填する必要がある.したがって,構造全体の大きさはsizeof(MyStruct)=8+1+3+4=16であり,そのうち3バイトがVCで自動的に埋め込まれ,意味のあるものは何も置かれていない.
例を挙げて、上のMyStructのメンバー変数の位置を交換して、次のようにします.
struct MyStruct
{
char dda;
double dda1;
int type
};
この構造が占有する空間はどのくらいですか?VC 6.0環境では、sizeof(MyStruc)が24であることが得られる.上述した分配空間のいくつかの原則を結びつけて、VCがどのように上の構造のために空間を分配するかを分析します.(簡単な説明)
struct MyStruct
{
char dda;// 0, ,dda 1 ;
double dda1;// 1, sizeof(double)=8
// , 7 8(
// ), VC 7 ,dda1 8
// , 8 。
int type;// 16, sizeof(int)=4
// , int , VC ,type
// 16 , 4 。
};//すべてのメンバー変数にはスペースが割り当てられています.スペースの合計サイズは1+7+8+4=20で、構造ではありません.
//のセクション境界数(すなわち、構造内で最大空間を占有するタイプが占有するバイト数sizeof
//(double)=8)の倍数なので、構造の大きさが
//sizeof(double)=8の倍数です.
従って、この構造の総サイズは、sizeof(MyStruc)が1+7+8+4+4=24である.このうち総7+4=11バイトはVCで自動的に埋め込まれ、意味のあるものは何も入っていません.
VCの構造に対する記憶の特殊な処理は確かにCPUが変数を記憶する速度を高めて、しかし時にはいくつか面倒をもたらして、私達も変数のデフォルトの位置合わせの方式を遮断して、自分で変数の位置合わせの方式を設定することができます.
VCには、変数をnバイトで整列するように設定するためのpragma pack(n)が設けられている.nバイトアライメントとは、変数が格納される先頭アドレスのオフセット量の2つのケースがある.第1に、nが変数が占有するバイト数以上である場合、オフセット量はデフォルトのアライメント方式を満たさなければならない.第2に、nが変数のタイプが占有するバイト数未満である場合、オフセット量はnの倍数であり、デフォルトのアライメント方式を満たさない.構造の合計サイズにも制約があり、nがすべてのメンバー変数タイプが占有するバイト数より大きい場合、構造の合計サイズは、占有空間が最大の変数が占有する空間数の倍数でなければならない.
そうでなければnの倍数でなければなりません.次に、その使い方を例に挙げて説明します.
pragma pack(push)/位置合わせ状態の保存
pragma pack(4)/4バイト揃えに設定
struct test
{
char m1;
double m4;
int m3;
};
pragma pack(pop)/位置合わせ状態の回復
以上の構成の大きさは16であり、以下ではその記憶状況を分析し、まずm 1に空間を割り当て、そのオフセット量は0であり、私たちが設定した位置合わせ方式(4バイト位置合わせ)を満たし、m 1は1バイトを占有する.次にm 4に空間を割り当て始めると、そのオフセット量は1であり、オフセット量がn=4の倍数(sizeof(double)がnより大きいため)を満たすように3バイト補完する必要があり、m 4は8バイトを占有する.次にm 3に空間を割り当てると,そのオフセット量は12であり,4の倍数を満たし,m 3は4バイトを占有する.このとき,すべてのメンバ変数に空間が割り当てられ,nの倍数を満たす16バイトが割り当てられた.上記の#pragma pack(4)を#pragma pack(16)に変更すると、構造の大きさは24となる.(読者自身で分析してください)
2、sizeof用法まとめ
VCではsizeofには多くの使い方があり、いくつかのエラーを引き起こしやすい.次にsizeofの後のパラメータに基づいてsizeofの使い方をまとめます.
A.パラメータはデータ型または一般変数です.たとえばsizeof(int)、sizeof(long)などです.この場合、異なるシステムシステムまたは異なるコンパイラで得られた結果は異なる可能性があることに注意してください.例えばintタイプは16ビットシステムで2バイト,32ビットシステムで4バイトである.
B.パラメータは配列またはポインタである.以下、例を挙げる説明する.
int a[50];//sizeof(a)=4*50=200;配列の占める空間の大きさを求めます
int *a=new int[50];//sizeof(a)=4; aは1つのポインタであり、sizeof(a)はポインタを求める
//のサイズは、32ビットシステムでは、もちろん4バイトです.
C.パラメータは構造またはクラスである.Sizeofがクラスや構造に適用される処理は同じである.しかし、静的変数の格納位置は、構造またはクラスのインスタンスアドレスとは無関係であるため、第1、構造またはクラスの静的メンバーは、構造またはクラスのサイズに影響を及ぼさない点に注意してください.
第二に、メンバー変数のない構造またはクラスのサイズは1であり、構造またはクラスの各
個のインスタンスには、メモリに一意のアドレスがあります.
次に例を挙げて説明します.
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,sはポインタです.
Class test1{ };//sizeof(test1)=1;