我在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;
}
Run Code Online (Sandbox Code Playgroud)
如果我在最后一行打破,并调试/检查这是我得到的
(gdb) print &a
$5 = (long *) 0xbffff04c
(gdb) print &c
$6 = 0xbffff04b "3\005"
(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
Run Code Online (Sandbox Code Playgroud)
c当只需要0xbffff04b来存储char 时,为什么为char保留0xbffff048,0xbffff049,0xbffff04a和0xbffff04b ?
这个符号"3\005"是什么意思?
另一方面,如果我的方法如下所示,对于具有三个额外字节存储的字符,没有填充
void addme()
{
long a = 5;
char c = '3';
char line[9];
char d = '4';
}
Run Code Online (Sandbox Code Playgroud)
这就是这些变量的内存分配方式(跳过地址的前导部分)
a - f04c
c - f04b
d - f04a
line - f041, f042, f043, f044, f045, f046, f047, f048, f049
Run Code Online (Sandbox Code Playgroud)
也不确定为什么在内存预留中d悬挂起来line.我假设因为它没有初始化,它会进入堆栈中的不同区域而不是初始化变量?
这称为对齐.对象与特定整数的倍数(通常为4或8 long)对齐,以便快速访问.通常,您不需要过多担心C++中的位置,因为语言规范通常使编译器能够选择最有效的(就您的优化方向而言)存储对象的方式,这通常就是这种情况.
每个对象类型都有称为对齐要求的属性,它是一个整数值(类型
std::size_t,总是幂2),表示可以分配此类对象的连续地址之间的字节数.可以使用alignof或查询类型的对齐要求std::alignment_of.指针对齐函数std::align可用于在某个缓冲区内获得适当对齐的指针,std::aligned_storage并可用于获得适当对齐的存储.每种对象类型都对该类型的每个对象强加其对齐要求; 可以使用更严格的对齐(具有更大的对齐要求)
alignas.为了满足类的所有非静态成员的对齐要求,可以在其一些成员之后插入填充.
关于你的第二个问题,@ prl给出了答案:
因为
c是achar,&c是achar *,所以gdb将其打印为字符串.字符串的第一个字符是'3',值是c.下一个字符是5,低字节a,gdb以八进制转义符号打印.在维基百科上的C中转义序列 - prl 1024分钟前
为什么在你声明chars之后垫子会消失char?因为在这种情况下,char对齐似乎是1,这意味着不需要填充.另一方面,它long看起来是4,所以必须有一个4字节的空间,char放置它.
我假设因为它没有初始化,它会进入堆栈中的不同区域而不是初始化变量?
并不是的.变量是否初始化(通常)不会影响其放置,只是它具有不确定的值.另一方面,编译器可以自由地将对象放在内存中.在实践中,编译器"享受"实现,从而在内存和时间方面提高效率.