別踩static的地雷

2021-04-12 11:49:54 字數 3265 閱讀 3159

只要做過專案的朋友對關鍵字static應該都有一些了解,但未見了解很全面的。在c語言中,關鍵字static有以下明顯的作用:1.static變數分配到靜態記憶體中,這一點和全域性非靜態變數相同。

2.在函式體,static變數只要不進行修改操作,在被呼叫過程中其值將保持不變。

3.在模組內,全域性static變數可以被模組內所有函式訪問,但不能被模組外其它函式訪問。它是乙個本地的全域性變數,具有私有特點。

4.在模組內,乙個static函式只可被這一模組內的其它函式呼叫。那就是,這個函式被限制在宣告它的模組的本地範圍內使用,也具有私有特點。

如果我們能夠很好地利用static的這些特性,書寫高內聚低耦合,更具模組化的**就不會顯得象句口號;如果不能很好地理解和使用它,一切都只是空談。下面來舉個例子來說明static在實際應用可能會遇到問題。

<------packet----->

| header | data |

我想有人可能會這麼做:

#define max_packet_size 1600

typedef struct _header

header;

boolsend(bool type,uint8* data,uint32 length) ;/

*定義陣列*/

header* pheader=(header*)

packet;

if(null==data || length<1)

/*設定包頭*/

pheader->type=type;

pheader->length=length;

pheader++;

memcpy((uint8*)pheader,data,length);/*拷貝資料到包頭之後*/

netsend(

packet);/*將包傳送到網路*/

return true; }

對於上面的**,有人可能會有這樣的疑慮,傳送資料報到網路是乙個非常頻繁的操作,所以在send函式中,頻繁地為

packet

分配棧記憶體是一種低效的做法。他可能會將上的**修改為:

boolsend(bool type,uint8* data,uint32 length)

packet= (uint8*)malloc(length+sizeof(header));

if(null==packet)

pheader=(header*)packet;

pheader->type=type;

pheader->length=length;

pheader++;

memcpy((uint8*)pheader,data,length);

net_send(

packet);/*將包傳送到網路*/

free(packet);

packet=null;

return true;

}使用動態記憶體好象可以解決上面的問題,但它沒有考慮到頻繁地使用malloc-free會產生大量的記憶體碎片。在嵌入式系統環境中,一般記憶體大小有限,所以這種做法最終會導致分配失敗。對於處理大流量資料問題,一種比較常用的高效方法就是在函式內部使用靜態陣列(全域性靜態陣列在這個應用中不建議使用,因為全域性變數會增加函式間的耦合度)。嘿嘿,聽到這樣的建議,估計有人會馬上這麼改:

boolsend(bool type,uint8* data,uint32 length) ;

header* pheader=(header*)

packet;

if(null==data || length<1)

pheader->type=type;

pheader->length=length;

pheader++;

memcpy((uint8*)pheader,data,length);

net_send(

packet);/*將包傳送到網路*/

memset(

packet,

0,sizeof(packet));/*清除本次記憶體操作*/

return true; }

朋友且慢,小心地雷!

你是否忘了考慮**可重入(reentrance)問題呢?這裡使用

packet

靜態陣列的確不用頻繁地分配動態或棧記憶體,但同時引入了**不可重入的問題。因為函式內的static變數分配在靜態記憶體區,供所有物件共用。在多工系統中,如果有乙個以上的任務同時訪問該記憶體,很可能會出現問題。所以我們必須要用其它手段來消除這個不可重入問題。使用訊號量semaphore是乙個很好解決不可重入問題的方法。在上面**中加入訊號量:

boolsend(bool type,uint8* data,uint32 length);

header* pheader=(header*)

packet;

if(null==data || length<1)

semtake(semaphore,wait_forever);/*等待訊號量*/

pheader->type=type;

pheader->length=length;

pheader++;

memcpy((uint8*)pheader,data,length);

net_send(

packet);/*將包傳送到網路*/

memset(

packet,

0,sizeof(packet));/*清除本次記憶體操作*/

semgive(semaphore);/*釋放訊號量*/

return true;

}踩過這個地雷,修改這個bug也化了很大功夫。

STM32程式設計常踩的地雷

1 宣告資料,但沒賦值就被使用,如下面的 u8 i for u8 i i 8 i 上面的示例 絕大部分時候,會如期輸出 0,1,2,3,4,5,6,7 但是 但是 但是 某個時候值不是這樣的,什麼值?什麼時候?2 先清中斷,後清中斷 void tim6 dac irqhandler void a位和...

急剎車是否踩離合器?別猶豫,踩。

原文 很多人遇到緊急情況時的第一反應就是要踩剎車,從沒想過要踩離合器。因為印象中在緊急情況下剎車如果踩下離合器的話,發動機的反拖制動消失會增加剎車距離,影響安全。也就是抱著這一想法我用一台手動擋的車進行了測試,測試專案就是緊急制動時100 0km h踩離合和不踩離合距離有沒有差異。流傳觀點 急剎車時...

jQuery實踐 別踩白塊兒網頁版

達人科技 2017 01 17 17 57 終於結束了考試,放假回家了。這次的別踩白塊兒網頁版要比之前做的 jquery實踐 網頁版2048小遊戲要簡單一點,基本的思路都差不多。這個小遊戲可以抽象化分為3層 最底下的一層是基本的樣式 可見的 中間的層是最主要的,是乙個4x3的二維陣列,遊戲中我們都是...