只要做過專案的朋友對關鍵字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的二維陣列,遊戲中我們都是...