函式返回指標型別與函式的可重入性

2021-08-01 00:27:24 字數 1552 閱讀 5868

在c和c++中,自動變數在堆疊中分配記憶體。當包含自動變數的函式或**塊退出時,它們所占用的記憶體便被**,它們的內容肯定會被下乙個所呼叫的函式覆蓋。這一切取決於堆疊中先前的自動變數位於何處,活動函式宣告了什麼變數,寫入了什麼內容等。原先自動變數位址的內容可能被立即覆蓋,也可能稍後才被覆蓋。

在c和c++中,陣列作為引數傳入函式或作為結果從函式中返回時,都會隱式使用到指標,即實際傳遞的是該陣列首個元素的位址。因此當函式返回乙個陣列的時候,實際返回的是指向陣列元素的指標,並不是乙個真正的陣列。

因此,當函式將執行結果儲存在陣列當中返回相應的指標的時候,需要確保這個陣列不是乙個在該函式的棧上分配的區域性變數。不然的話,在函式執行結束以後,該陣列的記憶體空間可能被重寫,從而使函式的返回結果變得無效。

避免這樣的問題的乙個方法是將陣列宣告為static型別,下面的例子就用到了這種方法,這個函式用於將internet位址轉換為以圓點分割的十進位制形式。

char *inet_ntoa(ad)

struct in_addr ad;

該函式將執行結果儲存在名為addr的緩衝區中,如果這個緩衝區沒有被宣告為static,則在函式返回以後,緩衝區的內容將會無效,返回的addr也就沒有實際的作用了。

當然除了使用上面介紹的將陣列的型別指定為static,還有其他的方法,可以參考這一篇文章。

下面我們將要從可重入性上來討論上述幾種方法。

使用全域性變數或靜態變數的函式在大多數情況下是不可重入的。也就是說,如果這個函式的乙個例項在執行,程式中的其他執行緒就不能夠呼叫這個函式。更為糟糕的是,在這個例子中,當該函式被再次呼叫前,函式的執行結果必須要儲存到其他地方,否則,這個結果將會被新的結果重寫,例如,在下面的**中,使用到nadd_ntoa函式的地方並不能使用上面的inet_ntoa函式來替換。

(void)fprintf(ftrace, "%s router ad"

" from %s to %s via %s life=%d\n",

act, naddr_ntoa(from), naddr_ntoa(to),

ifp ? ifp->int_name : "?",

ntohs(p->ad.icmp_ad_life));

為了避免前面提到的問題,naddr_ntos函式對inet_ntoa函式進行了包裝,將其執行結果儲存在由四個臨時緩衝區組成的迴圈列表當中。

/* convert ip address to a string, but not into a single buffer

*/char *

naddr_ntoa(naddr a)

bufs[num_bufs];

char *s;

struct in_addr addr;

addr.s_addr = a;

s = strcpy(bufs[bufno].str, inet_ntoa(addr));

bufno = (bufno+1) % num_bufs;

return s;

#undef num_bufs

}

可重入函式與不可重入函式

可重入 reentrant 函式可以由多於乙個任務併發使用,而不必擔心資料錯誤。相反,不可重入 non reentrant 函式不能由超過乙個任務所共享,除非能確保函式的互斥 或者使用訊號量,或者在 的關鍵部分禁用中斷 可重入函式可以在任意時刻被中斷,稍後再繼續執行,不會丟失資料。可重入函式要麼使用...

可重入函式與不可重入函式

可重入 可重新進入,也即兩次進入的現場一模一樣?在實時系統的設計中,經常會出現多個任務呼叫同乙個函式的情況。如果這個函式不幸被設計成為不可重入的函式的話,那麼不同任務呼叫這個函式時可能修改其他任務呼叫這個函式的資料,從而導致不可預料的後果。那麼什麼是可重入函式呢?所謂可重入是指乙個可以被多個任務呼叫...

不可重入函式 與 可重入函式

不可重入函式不可以在它還沒有返回就再次被呼叫 該函式在被呼叫還沒有結束之前,再次被呼叫,從而可能產生錯誤。但是,可重入函式不存在這樣的問題。不可重入函式在實現時通常使用了全域性的資源 eg.全域性變數 在多執行緒的環境下,如果沒有很好的處理資料保護和互斥訪問,就可能會發生錯誤。常見的不可重入函式有 ...