【C言語】構造体のメモリアラインメント

1. 構造体メモリのアライメント規則


1. 最初のメンバーは構造体変数からオフセット 0 のアドレスにある
2. 他のメンバー変数は特定の数 (アライメント番号) の整数倍のアドレス (オフセット) にアライメントされている必要がある gcc コンパイラには、デフォルトのアライメント番号がありません。メンバーのサイズは、アライメント番号です
。アライメント番号 = コンパイラのデフォルトのアライメント番号 (VS のデフォルトは 8) とメンバーのサイズの間の小さい値です。3. 構造体の合計サイズは
、最大アライメント数 (各メンバー変数はアライメント数の整数倍です)
4. 構造体がネストされている場合、ネストされた構造体はその最大アライメント数の整数倍にアライメントされ、構造体の全体のサイズは最大になります。すべてのアライメント番号 (入れ子構造を含む)、ボディのアライメント番号の整数倍)


次のコードを参照してください。

struct S1//结构体变量
{
    
    
	char c1;//1 c1 第一个成员
	int a;//4   4<8 对齐数为4  此时4为该结构体的最大对齐数
	char c2;//1 对齐数为1
};
struct S2
{
    
    
	char c1;//1
	char c2;//1
	int a;//4
};
#include<stdio.h>
int main()
{
    
    
	struct S1 s1 = {
    
     0 };
	printf("%d\n", sizeof(s1));
	struct S2 s2 = {
    
     0 };
	printf("%d\n", sizeof(s2));
	return 0;
}

操作結果:

12
8

説明 (S1 を例として):

  • 1. 最初のメンバーは、構造体変数からのアドレス オフセット 0 にあります。コード内のc1は最初のメンバーであり、c1は1バイトを占有するため、c1は下図の青い部分に格納されます。

  • 2. 他のメンバ変数は、ある数値(アライメント番号)の整数倍のアドレス(オフセット)にアライメントされる必要がありますが、gccコンパイラにはデフォルトのアライメント番号がありません。メンバのサイズがアライメント番号となります。
    アライメント番号 = コンパイラーのデフォルトのアライメント番号 (VS のデフォルトは 8) とメンバーのサイズの間の小さい値。
    私は VS を使用しているため、デフォルトのアライメント番号は 8 です。2 番目のメンバー c2 のサイズは 4、4<8 であるため、c2 のアラインメント番号は 4 となり、オフセット 4 の後に数値が格納されていないため、c2 はオフセット 4 の倍数である数値の格納を開始します。 c2 はオフセット 4 から格納され始め、c2 は 4 バイトを占有するため、c2 は下図の緑色の部分に格納されます。

  • 同様に、下図のオレンジ色の部分にc3が格納されます。

  • 3. 構造体の合計サイズは、最大アライメント番号の整数倍です (各メンバー変数にはアライメント番号があります)。ルールに従って c1 c2 c3 を格納すると、合計 1+4+1=6 バイトを占めるはずですが、結果は 12 になります。最初の 3 つの整列規則によれば、白い部分は空でなければならないため、この整列規則によれば、c2 のサイズが 4 で最大であるため、S1 の最大整列数は 4 になります。ルール、追加 上部の空白部分は 9 で、最も近い 4 の倍数は 12 なので、さらに 3 つの空白部分、つまり黄色の部分を追加する必要があります。

  • ここに画像の説明を挿入します

  • 要約すると、構造体 S1 のサイズは 12 です。

  • 計算の結果、c1とaの位置を変えるだけで構造の大きさが12から8に変わるので、できるだけ隙間の少ない部材を近づける必要があることがわかりました。


  • 4. 構造体がネストされており、ネストされた構造体がその最大アライメント数の整数倍にアライメントされている場合、構造体の全体のサイズは、すべての最大アライメント数 (ネストされた構造体のアライメント数を含む) の整数になります。コードを参照してください
    。 :
struct S3
{
    
    
	double d;//8
	char c;//1
	int i;//4
};
struct S4
{
    
    
	char c1;//1
	struct S3 s3;//16 最大对齐数为8 从偏移量为8的时候开始
	double d;//8
};
#include<stdio.h>
int main()
{
    
    
	struct S3 s3 = {
    
     0 };
	printf("%d\n", sizeof(s3));
	struct S4 s4 = {
    
     0 };
	printf("%d\n", sizeof(s4));
	return 0;
}

操作結果:

16
32

説明する:

  • 整列規則によれば、S3 のサイズは 16 であることがわかります。
  • S4 サイズを計算すると、16>8 となるため、アライメント番号は 8 になります。
  • S4 のサイズは 32 と同様に計算できます。

2. メモリアラインメントはなぜ存在するのでしょうか?

  • 1. プラットフォームの理由 (移植の理由): すべてのハードウェア プラットフォームが任意のアドレスのデータにアクセスできるわけではありません。一部のハードウェア プラットフォームは、特定のアドレスで特定の種類のデータしか取得できません。そうでない場合は、ハードウェア例外 2 がスローされます。パフォーマンスの理由: データ
    構造(特にスタック) は、可能な限り自然な境界に揃える必要があります。その理由は、アライメントされていないメモリにアクセスするには、プロセッサが 2 回のメモリ アクセスを行う必要があるのに対し、アライメントされたメモリ アクセスには 1 回のアクセスだけが必要であるためです。一般的に言えば、構造体
    のメモリ アライメントは、スペースと時間を交換することです。
  • では、構造を設計するときにスペースを節約しながら位置合わせを実現するにはどうすればよいでしょうか?
    1. スペースが狭いメンバーはできるだけ一緒に集める必要があります。
    2. デフォルトのアライメント番号 #pragma を変更します。通常は 2 のべき乗です。

おすすめ

転載: blog.csdn.net/m0_74102736/article/details/130451808