关于内存地址的问题

Questions regarding memory addresses

本文关键字:地址 问题 内存 于内存      更新时间:2023-10-16

基于以下代码,我有几个问题:

  1. 为什么&s->m1&s->m2之间的差异是4字节,而double的大小是8
  2. 为什么调整m3的大小不会更改地址?我预计&s->m4在调整m3的大小后会进一步偏移
  3. 为什么即使我删除了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
  1. sizeof(s->m2(是8个字节这一事实影响了&s->m2和&s->m3,而不是&s->m1和&s->m2.

  2. 调整m3的大小不会更改地址,因为std::vector使用动态堆内存来存储向量的内容。

  3. 如果删除m1,因为下一个结构元素m3位于8字节的边界上,编译器会添加4字节的填充以保持对齐。

哦。

首先,在访问说明符之间(我相信在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的起始地址。如果类型为intm1是4个字节,则下一项m2开始时至少高出4个字节。你的编译器也是如此。然而,编译器可以自由插入填充,因此m2可以放得更高。对于其他编译器,int可以是8个字节,甚至只有1个字节(它必须至少是16位,因此后一种可能性意味着char,即C++存储单元,至少是16个位,就像在一些德州仪器的数字信号处理器上一样(。

">2。为什么调整m3的大小不会更改地址?我预计CCD_ 20在调整CCD_ 21的大小后会进一步偏移。

C++中的所有对象都是固定大小的,由sizeof运算符给定。但它们可以保存指向内存块的指针,而内存块的大小可能会发生变化。m3std::vector,它使用这种技术:它保存一个指向某个内部缓冲区的指针。您可以通过.capacity()方法检查该缓冲区的大小。您可以通过.size()方法检查当前使用了多少。

">3。为什么即使我删除了m1,所有地址都保持不变?

如果观察结果正确,则可能是double类型的m2,以及编译器和编译选项,具有8个字节的对齐。也就是说,double必须放置在8的倍数的地址上。由于在m2之前仍然有int类型的m0,并且对于编译器,int是4个字节,因此编译器插入4个字节的填充

编译器不能为了更好的空间利用率而移动这些项,因为C++标准要求它将它们按递增的地址顺序放置,因为没有介入的访问说明符。

然而,大多数编译器支持各种#pragma来影响它们的填充和对齐决策。