C の関数はローカルのスタックベースの変数を使用する場合があり、必要なスペースの量だけスタック ポインターをデクリメントするだけで割り当てられることを読みました。これは常に4 バイトのチャンクで行われます(私が間違っていなければ)。しかし、次のようなコードを実行するとどうなるでしょうか。
void foo(void)
{
char str[6];
......
}
var がstr
占めるサイズは? 6
バイトまたは6 × 4
4 バイトのチャンクごとのバイト。
C の関数はローカルのスタックベースの変数を使用する場合があり、必要なスペースの量だけスタック ポインターをデクリメントするだけで割り当てられることを読みました。これは常に4 バイトのチャンクで行われます(私が間違っていなければ)。しかし、次のようなコードを実行するとどうなるでしょうか。
void foo(void)
{
char str[6];
......
}
var がstr
占めるサイズは? 6
バイトまたは6 × 4
4 バイトのチャンクごとのバイト。
4 バイト チャンク ルールは、スタック ポインターが 4 の倍数のアドレスを指している必要があることを意味します。この場合、8 バイトを割り当てることでその規則が満たされ、そのようなブロックは 2 バイトのパディングのみで 6 文字の配列を保持するのに十分な大きさになります。
データ アライメントは CPU 要件です。つまり、CPU ごとにアライメント量が変化することを覚えておいてください。
スタックのデータ配置について言えば、gcc
たとえば、データが配置される-mpreferred-stack-boundary=n
場所と呼ばれるオプションを使用してデータを配置したままにし2^n
ます。デフォルトでは、 の値n
は 4 で、スタック アラインメントは 16 バイトになります。
これが意味することは、明示的に割り当てたのは単なる整数であるにもかかわらず、スタック メモリに 16 バイトを割り当てていることに気付くということです。
int main()
{
char ar[6] = {1,2,3,4,5,6};
int x = 10;
int y = 12 + (int) ar[1] + x;
return y;
}
CPU で gcc を使用してこのコードをコンパイルすると、次のアセンブリが生成されます (スタック割り当て命令のみをポストします)。
subl $32, %esp
しかし、なぜ32?ちょうど 16 バイトに収まるデータを割り当てています。さて、gcc が保存しておく必要がある 8 バイトがありleave
、ret
これにより必要なメモリの合計は 24 になり
ます。しかし、
アラインメント要件は 16 バイトであるため、gcc はスタック領域を割り当てて、16 バイトのチャンクで構成されるようにする必要があります。 ; その 24 バイトを 32 にすると、問題が解決します。変数とand
用に十分なスペースがあり、2 つの 16 バイトのチャンクで構成されています。ret
leave
4 バイトのチャンクで割り当てる規則は、すべての場合に有効というわけではありません。たとえば、ARM eabi では、64 ビット整数と double を 8 バイト境界に配置する必要があります。
通常、割り当てられたスペースは、データを構造体にパッキングする規則と一致します。そのchar[6]
ため、実際には (通常は) 6 バイトかかりますが、データのパディング (次のフィールド用) にはさらに数バイトを使用できます。
例:
struct X
{
char field1[6];
};
したがって、構造の X サイズは次のようになります。8
structure Y
{
char field1[2];
double field2;
};
構造 Y は通常、アーキテクチャに応じて8
、12
またはバイトのようなものです。16
自動スタック変数にも同じ規則が適用されます。通常、パディングは使用している型ではなく、次に使用する型によって決定されます。また、ルールが少しあいまいな場合もあります。
あなたが持っている場合:
char str[6];
int a;
char b;
char c;
スタックは、これらすべての変数を含むのに十分なサイズであり、4 で割り切れます (または必要なアラインメント)。ただし、各変数を同じ境界に揃える必要はありません (ただし、ハードウェア要件がある場合があります)。
私のシステムでは、上記をコンパイルし、スタック変数のアドレスを出力します (簡潔にするために先頭の数字を削除しています):
&str -- 18
&a -- 12
&b -- 10
&c -- 11
つまり、コンパイラはスタックがアラインされるように調整しますが、変数をパディングする必要はありません。
データ サイズとデータの配置の間で混乱していると思います。一般的な規則はありませんが、最新のコンピューターでは、変数は 6 バイトで格納されます。一方、次の要素は必ずしも次のバイトに格納されるとは限りません。これは、データ構造パディングとして知られています。
すべての変数がワード サイズの倍数であるアドレスで開始する必要があるワード アラインアーキテクチャは、まれになりつつあります。SPARC や x86 などの新しいプロセッサでは、変数は自己整列されます。これは、型サイズの倍数であるアドレスで開始する必要があることを意味します。
したがって、非エキゾチックなコンピューターには「4 バイト チャック ルール」はありません。あなたの例でstr
は、6バイトで保存されます。たとえば ( double
x86 などで) 8 バイトのアラインメントで変数を宣言すると、コンパイラによって 2 つのパディング バイトが挿入されます。
アライメントは、アーキテクチャに応じてコンパイラによって修正されます。したがって、標準はそれについて何も定義していません。詳細については、Wikipediaを参照してください。