爲什麼兩次調用sbrk(0)會得出不同的值?

在學習函數 sbrk() 的時候,我們知道:

void *sbrk (intptr_t increment);
  • 當 increment 爲正時,則按 increment 的大小,開闢內存空間,並返回開闢前,程序中斷點(program break)的地址。
  • 當 increment 爲負時,則按 increment 的大小,釋放內存空間,並返回釋放前,程序中斷點的地址。
  • 當 increment 爲零時,不會分配或釋放空間,返回當前程序中斷點的地址。

那麼寫一下測試代碼,【示例一】:

#include <unistd.h>
#include <stdio.h>

int main() {
    printf("sbrk(0) = %p\n", sbrk(0)); // 應該返回 x
    printf("sbrk(0) = %p\n", sbrk(0)); // 應該返回 x
    printf("sbrk(5) = %p\n", sbrk(5)); // 應該返回 x
    printf("sbrk(0) = %p\n", sbrk(0)); // 應該返回 x + 5
    return 0;
}

預期得到類似這樣的結果:

sbrk(0) = 0x1985000
sbrk(0) = 0x1985000
sbrk(5) = 0x1985000
sbrk(0) = 0x1985005

但是輸出卻是這樣的:

sbrk(0) = 0x1985000
sbrk(0) = 0x19a6000
sbrk(5) = 0x19a6000
sbrk(0) = 0x19a6005

換一個寫法,將地址存儲在變量中,【示例二】:

#include <unistd.h>
#include <stdio.h>

int main() {
    void *toto1 = sbrk(0);
    void *toto2 = sbrk(0);
    void *toto3 = sbrk(5);
    void *toto4 = sbrk(0);

    printf("sbrk(0) = %p\n", toto1);
    printf("sbrk(0) = %p\n", toto2);
    printf("sbrk(5) = %p\n", toto3);
    printf("sbrk(0) = %p\n", toto4);
}

輸出結果:

sbrk(0) = 0x617000
sbrk(0) = 0x617000
sbrk(5) = 0x617000
sbrk(0) = 0x617005

這纔是我們預想的一樣,那爲什麼會出現這種情況呢?

其實出現這個問題的原因:是 printf 的鍋!

  1. 【示例一】的代碼,爲什麼前兩次調用 sbrk(0) 沒有返回相同的值?
    在第一次調用 printf 函數時,內部分配一個緩衝區 stdout,創建緩衝器的時候調用了 malloc,而 malloc 內部又調用了 brk 分配內存。

  2. 【示例一】的代碼,爲什麼後面再多次調用 printf 沒有產生變化?
    這是因爲,默認情況下,stdout 是行緩衝,並且緩衝區是在第一次打印時按需創建的,後面不論多少次調用 printf ,緩衝區都已完成創建。

  3. 【示例二】的代碼,爲什麼輸出是正確的?
    sbrkprintf 之前調用,因此,其他函數的 malloc 是在分配空間之後進行,不會對輸出結果造成影響。


參考資料:Why does calling sbrk(0) twice give a different value?

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