有趣的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

這件事給我的感觸就是有一些細節一定不要放過,認真探索下去說不定會發現點以前沒注意到過的新東西

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章