有趣的内存对齐面试题

有趣的内存对齐面试题

题目描述:

内存对齐机制是一个用空间换取时间的做法,具体怎么做的,或者为什么要这么做?可以参考我的博客:内存对齐

这道题是这样的:问程序会在那么地方崩溃?

如果你直接答:那么你就错了兄弟。这道题是分平台的。我们先在Linux CentOS X86_64位平台下运行一下试试看。

#include <iostream>

struct S
{
    int a;
    int *p;
};

int main(void)
{
    struct S s;
    int *p = &s.a;

    p[0] = 1;
    p[1] = 2;

    s.p = p;
    s.p[1] = 1;
    s.p[0] = 2;

    std::cout << "a : " << s.a << "  p : " << s.p << std::endl;
    return 0;
}

在这里插入图片描述

程序并没有崩溃呀?

但是!如果把结构体的int改为long再看!

#include <iostream>

struct S
{
    long a;
    long *p;
};

int main(void)
{
    struct S s;
    long *p = &s.a;

    p[0] = 1;
    p[1] = 2;

    s.p = p;
    s.p[1] = 1;
    s.p[0] = 2;

    std::cout << "a : " << s.a << "  p : " << s.p << std::endl;
    return 0;
}

在这里插入图片描述

这是为什么呢??

再将这个原因之前,我们来看一下在CentOS x86_64位平台下,这些变量的大小分别是多少。

    std::cout << "int    : " << sizeof(int) << std::endl;
    std::cout << "int*   : " << sizeof(int *) << std::endl;
    std::cout << "long   : " << sizeof(long) << std::endl;
    std::cout << "long*  : " << sizeof(long*) << std::endl;

在这里插入图片描述

题目解释:

为了方便起见,我们将程序移到VS下,因为VS可以配置x86 和 x64切换。实现双平台。

32位平台下

因为在32位平台下,intint*都是4个字节,所以他们在内存中的存储是这样的。

在这里插入图片描述

我们通过编译器的监视窗口也可以看到。

在这里插入图片描述

所以当程序运行时:在这里插入图片描述

s.p[1] 其实就等于s.p。那个指针赋值就已经把这个结构体的首地址赋给s.p了,s.p[1]就相当于从结构体s的首地址开始向后走4个字节,那不就是s.p嘛。然后s.p[1] = 1,就相当于把自己的地址改成1了。然后在s.p[0]这个解引用操作的时候无法给1这个地址解引用,所以发生段错误。

64位平台下

但是在64位平台下,int为4个字节,int*为8个字节。所以他在内存中的存储是这样的。

在这里插入图片描述

监视窗口同样可以体现:

在这里插入图片描述

两个地址隔了8个字节,但是a只占4个字节,所以,p对齐到偏移量为8的地址处了。

那么我们再看刚才的程序:

在这里插入图片描述

当程序运行到这里的时候:(看内存窗口)

在这里插入图片描述

s.[1]只是改的是,s.a后面填充的4个字节,并没有改s.p,所以当然不会发生段错误呀。

小结:所以这个面试题还是很坑的。

你要想清楚,是不是不同平台下结果不一样。所以在面试的时候,还是要多考虑考虑不同的情况。

叮~上菜!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值