有趣的printf

sbrk()是linux上malloc的实现中用到的一个函数,sbrk(0)返回的是当前break的地址,今天我无意中多次打印sbrk(0)的值,发现结果和预想中的不太一样

printf("%p\n", sbrk(0));
printf("%p\n", sbrk(0));
printf("%p\n", sbrk(0));
printf("%p\n", sbrk(0));

运行这段代码,打印出来的却是

0x218b190
0x21ad000
0x21ad000
0x21ad000

很奇怪的一件事情,难道这四个输出不应该是一样的么?为什么第一个和其他的不同而剩下的几个相同呢?于是google了一下,虽然没有找到一样的,但是在stackoverflow找到一个差不多情况的帖子,那个人用sbrk申请了一个小空间,但是捣鼓捣鼓打印出来之后发现实际申请的空间比预想中的要多,下面有个大神解决了他的疑问,当然他的解答也适合于我的疑问。

原因就在于,我们使用的编译器的printf的内部实现可能使用了malloc(例如创建缓冲区),而malloc调用了sbrk(),在heap上申请了内存,所以第一次调用printf()之后堆被改变了,但是第一次打印时打印的是堆被printf改变之前的break地址,但此时break地址已经被改变了。

接下来的几次printf()调用可能对该缓冲区进行了复用所以不用再次改变堆,所以打印的一直是上次break被改变之后的地址。

再写一段代码证明这个猜想:

void *fuck = sbrk(0);
void *shit = sbrk(0);
printf("%p\n", sbrk(0));
printf("%p\n", sbrk(0));

printf("%p\n", shit);
printf("%p\n", fuck);


printf("%p\n", sbrk(0));

输出印证了这个猜想是正确的:

0x106c190
0x108e000
0x106c190
0x106c190
0x108e000

这件事给我的感触就是有一些细节一定不要放过,认真探索下去说不定会发现点以前没注意到过的新东西

猜你喜欢

转载自blog.csdn.net/u010742342/article/details/72598657