根据以下代码,我几乎没有问题:
&s->m1
和&s->m2
之间的差异为4个字节,double
的大小为8?m3
大小不会更改地址?我希望&s->m4
在调整m3
。m1
所有地址都保持不变?main.cpp中:
#include <iostream>
#include <vector>
struct S
{
int m0;
int m1;
double m2;
std::vector<int> m3;
std::vector<int> m4;
};
int main()
{
S* s = new S();
s->m3.resize(7);
std::cout << &s->m0 << std::endl;
std::cout << &s->m1 << std::endl;
std::cout << &s->m2 << std::endl;
std::cout << &s->m3 << std::endl;
std::cout << &s->m4 << std::endl;
return 0;
}
输出:
0x1860c20
0x1860c24
0x1860c28
0x1860c30
0x1860c48
答案 0 :(得分:4)
sizeof(s-> m2)为8字节的事实影响&amp; s-&gt; m2和&amp; s-&gt; m3之间的差异,而不是&amp; s-&gt;之间的差异。 m1和&amp; s-&gt; m2。
调整m3大小不会改变地址,因为std :: vector使用动态堆内存来存储向量的内容。
如果删除m1,因为下一个struct element m3在8字节边界上,编译器会添加4个字节的填充以保持对齐。
答案 1 :(得分:1)
喔。
嗯,首先,在访问说明符之间(我相信C ++ 11及更高版本对所有具有相同访问权限的项目),结构中的项目放在严格增加的内存地址,就程序本身而言
然后,给出你的声明
struct S
{
int m0;
int m1;
double m2;
std::vector<int> m3;
std::vector<int> m4;
};
...你问
“ 1.为什么
&s->m1
和&s->m2
之间的差异为4个字节,double
的大小为8?
对象的地址是该对象的起始地址,即其第一个字节的地址,即该对象中的最低地址。
因此m1
的地址是m1
开始的地方。如果类型为m1
的{{1}}为4个字节,则下一个项int
的开始时间至少增加4个字节。所以它与你的编译器一样。然而,编译器可以自由插入填充,因此m2
可以放得更高。对于其他一些编译器,m2
可以是8个字节,或者甚至只是1个字节(它必须至少为16位,所以后一种可能性意味着int
,即C ++内存单元,那么至少有16位,就像德州仪器的一些数字信号处理器那样。)
“ 2.为什么调整大小
char
不会更改地址?我希望m3
在调整&s->m4
之后能够进一步远离。{/ p>
C ++中的所有对象都是固定大小的,由m3
运算符给出。但是它们可以保存指向内存块的指针,这些指针实际上可以在大小上变化。 sizeof
是m3
,它使用这种技术:它包含指向某个内部缓冲区的指针。您可以通过std::vector
方法检查该缓冲区的大小。您可以通过.capacity()
方法检查当前使用的数量。
“ 3.为什么即使我删除
.size()
所有地址都保持不变?
如果该观察结果是正确的,那么类型m1
的大概m2
与您的编译器和编译选项的对齐为8个字节。也就是说,double
必须放在8的倍数地址上。并且由于double
之前仍有m0
类型int
,因此你的编译器m2
是4个字节,编译器插入4个字节的填充。
编译器无法移动这些项目以获得更好的空间利用率,因为C ++标准要求它将它们置于递增的地址顺序中,因为没有中间访问说明符。
但是,大多数编译器支持各种int
来影响其填充和对齐决策。