堆栈中的自动变量占用了多少内存空间

时间:2013-03-24 16:44:07

标签: c function compiler-construction stack local-variables

我读到C中的函数可能使用基于堆栈的本地变量,并且只需通过将堆栈指针递减所需的空间量来分配它们。这总是在四字节块中完成(如果我没有记错的话)。但是,如果运行如下代码:

 void foo(void)
{
   char str[6];
   ......
}

var str的大小是多少?根据四字节块,6个字节或6 × 4个字节。

5 个答案:

答案 0 :(得分:2)

四字节块规则只意味着堆栈指针必须指向一个4的倍数的地址。在这种情况下,分配8个字节满足该规则,并且这样的块足够大以容纳6个字符的数组,只有2个字节的填充。

答案 1 :(得分:2)

数据对齐是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需要为leaveret保存8个字节,这使得所需的总内存为24。
但是,对齐要求是16字节,因此gcc需要分配堆栈空间,以便它由16个字节的块组成;使24字节到32解决问题 对于retleave,您将拥有足够的空间用于变量,并且它由两个16字节的块组成。

答案 2 :(得分:0)

我猜您在数据大小数据对齐之间感到困惑。没有一般规则,但是,在现代计算机上,您的变量将以6个字节存储。另一方面,下一个元素不一定存储在下一个字节中。这称为数据结构填充

字对齐体系结构,其中每个变量必须从字长的倍数开始,变得越来越少。使用SPARC或x86等新处理器,变量自对齐。这意味着他们必须从一个地址开始,该地址是其类型大小的倍数。

因此,在非外来计算机上没有“四字节吸盘规则”。在您的示例中,str将以6个字节存储。例如,如果声明一个对齐为8字节的变量(例如x86上的double),则编译器将插入2个填充字节。

根据您的体系结构,编译器会修复对齐方式。所以标准没有定义任何关于它的内容。您可以在Wikipedia找到更多信息。

答案 3 :(得分:0)

以4字节块分配的规则在所有情况下都无效。例如,ARM eabi需要对比为64位整数,并在8字节边界上加倍。

通常,分配的空间与数据打包到结构中的规则相匹配。所以char[6]实际上需要6个字节(通常),但数据的填充(对于下一个字段)可以使用更少的字节。

示例:

struct X
{
    char field1[6];
};

因此结构X大小为8

structure Y
{
    char field1[2];
    double field2;
};

结构Y通常类似于81216字节,具体取决于架构。

相同的规则应用于自动堆栈变量:通常填充不是由您使用的类型决定的,而是由您将要使用的下一种类型决定。规则有时候有点模糊。

答案 4 :(得分:0)

如果你有:

char str[6];
int a;
char b;
char c;

堆栈的大小足以包含所有这些变量,并且可以被4整除(或者需要任何对齐)。但是每个变量不需要在同一边界上对齐(尽管可能有硬件要求)。

在我的系统上,编译上面的内容并打印出堆栈变量的地址(为简洁起见,删除了前导数字):

&str    -- 18
&a      -- 12
&b      -- 10
&c      -- 11

即编译器会安排堆栈对齐,但不需要填充变量。