一道很有意思的C++面试题

原题目为《程序员面试宝典》第7章面试题9:

struct S{
    int i;
    int *p;
};
main()
{
    S s;
    int *p =&s.i;
    p[0] = 4;
    p[1] = 3;
    s.p = p;
    s.p[1] = 1;
    s.p[0] = 2;
}

问程序会在哪一行崩溃?

第一次做这道题时我崩溃了:),脑子里全是糊的!好在VS提供了调试功能:

进行到图中步骤后,注意p指向的地址就是&s也就是&s.i,经过了p[0]=4;p[1]=3赋值后,可以看到是s.p指向的是未声明的空间0x00000003,而s.i的值就是4;

在经过了s.p = p;后:

可以发现s.p指向的地址也变成了0x00c7fd60,对s.p[1]=1;实际上就是对s.p赋值1:

显然,这时候是无法再执行s.p[0] = 2;了因为0x00000001空间根本就未声明。

*********************************************************************************************************************************************

扫描二维码关注公众号,回复: 3252028 查看本文章

原本这个问题就这么解决了,可我今天复习时,在deepin15.6下跑了一下这个程序,居然能通过了......

但是,敏锐的我很快就意识到了问题所在:å¯è¾¾é¸­ç头ä¸ç±ï¼åç°äºæ并ä¸ç®åï¼_ç头ä¸ç±_å¯è¾¾_ç®å表æ

因为在GDB调试下发现,结构体S s里int i和int *p的地址差了8而不是4,作为一个在面试中被sizeof坑过的boy,我马上就想到了deepin是64位系统啊,这样一个指针是8字节!

很明显,字节对齐的规则把这个致命的bug掩盖了。

在64位系统下,S中内存分布如下图所示:

1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1
int i               int *p              

可以观察到&s和&s.p之间差了8个字节(0x000000079152ff630 - 0x000000079152ff628)。

在32位系统下致命的s.p[1]=1;在64位系统下成为了一句不痛不痒的赋值,接下来的s.p[0] = 2;也就可以执行了。

********************************************************************************************************************

那么,怎么样复现这个bug呢?

按照上述分析,我们可以这样做:

struct S {
	int i;
	int *p;
};
int main()
{
	S s;
	int *p = &s.i;
	p[0] = 4;
	p[1] = 3;
	p[2] = 2;
	s.p = p;
	s.p[2] = 1;
	s.p[0] = 2;
}

但是且慢!能不能有更有逼格的方式呢?

#pragma pack(push)
#pragma pack(4)
struct S {
	int i;
	int *p;
};
int main()
{
	S s;
	int *p = &s.i;
	p[0] = 4;
	p[1] = 3;
	s.p = p;
	s.p[1] = 1;
	s.p[0] = 2;
}
#pragma pack(pop)

就是使用pragma pack改变对齐规则啦!

猜你喜欢

转载自blog.csdn.net/qq_21602549/article/details/81814002