为什么堆栈中的函数局部变量之间存在内存空间

Why is there a memory space between my function local variables in the stack?

本文关键字:之间 存在 内存 空间 局部变量 函数 堆栈 为什么      更新时间:2023-10-16

我在Ubuntu x86上用gcc编译了一个C程序。这是我从main调用的函数

void addme()
{
long a = 5;
char c = '3';
long array[3];
array[0] = 2;
array[1] = 4;
array[2] = 8;
}

如果我在最后一行中断,并调试/检查这就是我得到的

(gdb) print &a
$5 = (long *) 0xbffff04c
(gdb) print &c
$6 = 0xbffff04b "305"
(gdb) print &array
$7 = (long (*)[3]) 0xbffff03c
(gdb) x 0xbffff03c
0xbffff03c:     0x00000002
(gdb) x 0xbffff040
0xbffff040:     0x00000004
(gdb) x 0xbffff044
0xbffff044:     0x00000008
(gdb) x 0xbffff04c
0xbffff04c:     0x00000005

当只需要0xbffff04b来存储一个字符时,为什么要为字符c保留0xbffff448、0xbffff049、0xbfff f04a和0xbfffff f04b?

这个符号"305"是什么意思?

另一方面,如果我的方法如下,则不需要为字符填充三个额外字节的存储

void addme()
{
long a = 5;
char c = '3';
char line[9];
char d = '4';
}

这就是这些变量的内存分配情况(跳过地址的前导部分)

a - f04c 
c - f04b 
d - f04a 
line - f041, f042, f043, f044, f045, f046, f047, f048, f049

也不确定为什么在内存预留中d被提升到line之上。我想,因为它没有初始化,所以它会进入堆栈中与初始化变量不同的区域?

这被称为对齐。对象与特定整数的倍数对齐(在long的情况下通常为4或8),以便快速访问。一般来说,您不需要太担心C++中的位置,因为语言规范通常使编译器能够选择最有效的(就优化方向而言)存储对象的方式,通常就是这种情况。

每个对象类型都有一个名为对齐要求的属性,它是一个整数值(类型为std::size_t,总是2的幂),表示可以分配此类型对象的连续地址之间的字节数。可以使用alignofstd::alignment_of查询类型的对齐要求。指针对齐函数std::align可用于在某个缓冲器内获得适当对齐的指针,而std::aligned_storage可用于获得适当对齐存储。

每个对象类型都将其对齐要求强加给该类型的每个对象;可以使用CCD_ 13来请求更严格的对准(具有更大的对准要求)。

为了满足类的所有非静态成员的对齐要求,可以在其某些成员之后插入填充

(cppreference)


关于您的第二个问题,@prl给出答案:

因为cchar&cchar *,所以gdb将其打印为字符串。字符串的第一个字符是"3",即c的值。下一个字符是5,a的低字节,gdb以八进制转义表示法打印维基百科上C中的转义序列–1024分钟前


当您在char之后声明chars时,焊盘为什么会消失?因为在这种情况下,char的对齐方式看起来是1,这意味着不需要填充。另一方面,long看起来是4,所以必须有一个4字节的空间,其中放置了char

我认为,因为它没有初始化,所以它在堆栈中的区域与初始化的变量不同?

不是。变量是否初始化(通常)不会影响其位置,只会影响其值不确定。另一方面,编译器可以自由地按照自己喜欢的方式将对象放置在内存中。在实践中,编译器"享受";在内存和时间上都能提高效率的实现。