[セットトップ]構造体がメモリに占めるバイトサイズの計算

4775 ワード

著者:卿篤軍
今日の授業で、先生は私たちに構造体がメモリに占めるバイトサイズを計算することを実証しました.いくつかの例をあげて、それから私たち自身で法則を模索しなければなりません.
注意:以下のテストはすべてwin 7_です.64 bit Devcpp 5.5..3環境でテストした.(char 1バイト、int 4バイト、double 8バイト).
もしかすると、次の答えは1+4=5だと思います.×)
#include <stdio.h>

struct node
{
	char a;
	int b;
};

int main()
{
	struct node QING;
	
	printf("%d
",sizeof(QING)); return 0; }

実は、この問題の答えは:8(
√)
これは1つの構造体のバイトの位置合わせの問題に関連して、具体的な構造体はどうしてバイトの位置合わせをして、またどのように位置合わせして、次の2つの文章(私のネット上で探した)を参考にすることができます:
1.海が広く魚が跳ね、天が高く鳥が飛ぶブログのコラム、構造体がメモリに占める空間の大きさの計算、http://blog.csdn.net/onlyanyz/article/details/8159240
2.Eliotのブログコラム、構造体バイト揃え、http://blog.csdn.net/xyw_blog/article/details/20445953
ある構造体が占める空間をsizeof演算子で求める場合、構造体内のすべての要素がそれぞれ占める空間を単純に加算するのではなく、メモリバイトの位置合わせの問題に関連する.理論的には、任意の変数へのアクセスは任意のアドレスから開始できますが、実際にはそうではありません.実際には、特定のタイプの変数にアクセスするには、特定のアドレスにのみアクセスできます.これは、メモリの位置合わせではなく、空間的に一定の規則で配列する必要があります.
メモリの位置合わせの原因:1)一部のプラットフォームは特定のアドレスでしか特定のタイプのデータにアクセスできない.2)データへのアクセス速度の向上.例えば、あるプラットフォームは毎回偶数アドレスからデータを読み出し、int型の変数に対して、偶数アドレスユニットから格納すれば、1つの読み出し周期でその変数を読み取ることができる.ただし、奇アドレスユニットから格納すると、この変数を2リードサイクルで読み出す必要がある.
例として、位置合わせ方法を説明しましょう.

例1、char、int位置合わせ;

#include <stdio.h>

struct node
{
	char a;
	int b;
};

int main()
{
	struct node QING;
	
	printf("%d
",sizeof(QING)); return 0; }

出力結果:8
解釈:構造体では(変数定義の順序に注意)、charは1バイト、intは4バイト、構造体バイト位置合わせ:charとint位置合わせです.だからcharを4バイトに補完します.
したがって、最後の構造体が占めるバイト:4+4=8;

例2、char*、int位置合わせ;

#include <stdio.h>

struct node
{
	char a[5];
	int b;
};

int main()
{
	struct node QING;
	
	printf("%d
",sizeof(QING)); return 0; }

出力結果:12
解釈:構造体中のchar a[4]は、すでに下のintと位置合わせされているが、まだ1つのchar a[1]が残っているのもint(4)に揃える必要がある.
結果:8+4=12

例3、char、int、double整列;

#include <stdio.h>

struct node
{
	char a;
	int b;
	double c;
};

int main()
{
	struct node QING;
	
	printf("%d
",sizeof(QING)); return 0; }

出力結果:16
解釈:構造体のchar,intの2バイト数(全体)は、次のdoubleに位置合わせされます.したがってchar,int全体のバイト数は8に足りる.
結果:8+8=16

例4、char、double、int整列;

#include <stdio.h>

struct node
{
	char a;
	double c;
	int b;
};

int main()
{
	struct node QING;
	
	printf("%d
",sizeof(QING)); return 0; }

出力結果:24
例3を比較すると,構造体内の定義順序が変わっただけで,結果の相違をもたらすことが分かった.では、これはなぜですか.
実は、上のcharはdoubleに揃えるので、charバイトはdouble(8)に揃える必要がありますが、doubleは下のintに揃えることはできませんよね?doubleはもともとintより大きいので、揃えることは不可能ですが、intとdoubleだけが揃うので、intもdouble(8)に揃えるようにしましょう.
結果:8+8+8=24
ちなみに、C++のクラスサイズの計算:
1)一般的な状況~~~~
#include <iostream>
using namespace std;

class Test1
{
private:
	int a;
	int b;
};

int main()
{
	cout<<sizeof(Test1)<<endl;

	return 0;
}
出力結果:8(これは分析しなくてもいいでしょう)
2)一般メンバー関数を含むクラス:
#include <iostream>
using namespace std;

class Test2
{
public: 
	void SetXXX() { cout<<"Set"<<endl; }   // 
	int GetXXX() { cout<<"Get"<<endl; }
private:
	int a;
	int b;
};

int main()
{
	cout<<sizeof(Test2)<<endl;

	return 0;
}
出力結果:8
分析:クラス内のメンバー関数、クラス空間を占めない、メンバー関数、コード領域に格納......
3)虚関数を含むクラス:
#include <iostream>
using namespace std;

class Test3
{
public: 
	virtual void Print() { cout<<"Virtual"<<endl; }
private:
	int a;
	int b;
};

int main()
{
	cout<<sizeof(Test3)<<endl;

	return 0;
}
出力結果:12
解析:虚関数が含まれている場合は、必ず虚ポインタがあります.ポインタはアドレスを格納するためのもので、アドレスはすべて1つの整数値なので、ポインタのはすべて4バイトを占めています~~~
4)複数の虚関数を含むクラス:
#include <iostream>
using namespace std;

class Test4
{
public: 
	virtual void Print1() { cout<<"Virtual"<<endl; }
	virtual void Print2() { cout<<"Virtual"<<endl; }
	virtual void Print3() { cout<<"Virtual"<<endl; }
private:
	int a;
	int b;
};

int main()
{
	cout<<sizeof(Test4)<<endl;

	return 0;
}
出力結果:12
解析:どれだけの虚関数が含まれているかにかかわらず、虚ポインタは1つ、すなわち+4バイトしかありません.
5)空のクラス:
#include <iostream>
using namespace std;

class Test5
{

};

int main()
{
	cout<<sizeof(Test5)<<endl;

	return 0;
}
出力結果:1
分析:空のクラス、C++はクラスに1つの空間を予約します.
6)静的メンバーを含むクラス:
#include <iostream>
using namespace std;

class Test6
{
private:
	static int a;
};

int main()
{
	cout<<sizeof(Test6)<<endl;

	return 0;
}
出力結果:1
解析:実はこれは上のケース5と同じで、staticはクラス空間の中に属していないので、静的領域に保存されています~~~