C語言編程技巧

 C語言編程技巧

 

 

volatile的用法

 

volatile的本意是易變的EETOP專業博客---電子工程師自己的家園!~XP0Z,|Rz[#p‑~
M7p e6W{5d#k'^0
由於訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化。比如:EETOP專業博客---電子工程師自己的家園9x+Q%ww_

static int i=0;jt[1]Y/W V5y1t0EETOP專業博客---電子工程師自己的家園$`7@(jC/w7G0hf
int main(void)EETOP
專業博客---電子工程師自己的家園'C,yk


@4x U­M+]
{ ,Q,](b4J!? z p@0...
       !xN"N~h[1]d;[0while (1)
     ‑W­MG3S&^P-U7w&C0{EETOP
專業博客---電子工程師自己的家園f/\h Zd*E
         if (i) dosomething();
     6mCWh I


~0}
1f&]I)t5Z0x&q^[1]c)T0}EETOP專業博客---電子工程師自己的家園0N-O$P'r2r8Pq/O8t

iu^ `i f [0/* Interrupt service routine. */EETOP
專業博客---電子工程師自己的家園T}+i6MY
void ISR_2(void)
$v%^#{*IM4k­u i0{EETOP
專業博客---電子工程師自己的家園C:j(u\ b:`
    i=1;EETOP
專業博客---電子工程師自己的家園6A!G#w­?C-? }&kO
}cQM(ED"A0
#x3ix"?@)J‑Tk E I0
程序的本意是希望ISR_2中斷產生時,main當中調用dosomething函數,但是,由於編譯器判斷在main函數裏面沒有修改過i,因此可能只執行一次對從i到某寄存器的讀操作,然後每次if判斷都只使用這個寄存器裏面的“i副本”,導致dosomething永遠也不會被調用。如果將將變量加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優化(肯定執行)。此例中i也應該如此說明。+Z{­e[,{/IzB0EETOP專業博客---電子工程師自己的家園
ADw
VWf;[w&s8R

一般說來,volatile用在如下的幾個地方:y­\&V.atr,?-\*V0EETOP專業博客---電子工程師自己的家園(A-RcO&uY
1
、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;EETOP專業博客---電子工程師自己的家園n?b'w'Aw‑A"u
b3HT:lj,v(K02
、多任務環境下各任務間共享的標誌應該加volatile;*c S.M'Y(r0EETOP專業博客---電子工程師自己的家園;t5g)AW'Ko­}
?9m1Ha

3
、存儲器映射的硬件寄存器通常也要加volatile說明,因爲每次對它的讀寫都可能由不同意義;EETOP專業博客---電子工程師自己的家園E*v |8j2v$b
7_6\#Y;~%p%j­V[1]]:Upf0
另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標誌讀了一半被打斷了重寫),1中可以通過關中斷來實現,2中可以禁止任務調度,3中則只能依靠硬件的良好設計了。

 

 

 

關於C++中的內聯函數(inline)

 

c++中,爲了解決一些頻繁調用的小函數大量消耗棧空間或者是叫棧內存的問題,特別的引入了inline修飾符,表示爲內聯函數。 ]&CMg[1]R6s%MU0
8O
I'D+eC&N3{‑X6c*k0
  可能說到這裏,很多人還不明白什麼是棧空間,其實棧空間就是指放置程序的局部數據也就是函數內數據的內存空間,在系統下,棧空間是有限的,如果頻繁大量的使用就會造成因棧空間不足所造成的程序出錯的問題,函數的死循環遞歸調用的最終結果就是導致棧內存空間枯竭。

  下面我們來看一個例子:

#include <iostream
cR Y+Y']1ba&h+Hh3L0#include <
string
VHN&Z+J*u5e0
using namespace std; 


OS7a2RD{(~ J5}'M*{
6A \(Z$B6B0inline string dbtest(int a); //函數原形聲明爲inline:內聯函數  %E[1]_'S{#Bq0K4c6lx k3N0  EETOP專業博客---電子工程師自己的家園8U
A@


dg/M9U3J8p eM7Z  EETOP專業博客---電子工程師自己的家園+o%H)E?-I+V1a*]x
void main() 
:r Y Q&Oz*^Fs|'HN0
5M [|UXx[1]j|o0    
for (int i=1;i<=10;i++) 
,p y3sc‑pHK)`&C0    {  EETOP
專業博客---電子工程師自己的家園-I6J
I:S5E2_ G.C
K8^
l

        
cout << i << ":" << dbtest(i) << endl; 

Bk"a‑Z/cr9Q0
    }  EETOP
專業博客---電子工程師自己的家園C6~ SN6?$]l
    
cin.get();  EETOP專業博客---電子工程師自己的家園[1]O}h E2v7p"g
 

m`X!k,o$PlI0
EETOP
專業博客---電子工程師自己的家園
t!s.o-if#X.|EETOP
專業博客---電子工程師自己的家園­p;X;yHu
string dbtest(int a)//這裏不用再次inline,當然加上inline也是不會出錯的  EETOP專業博客---電子工程師自己的家園5D(TGk(u:Bw)F8w&i

7L2b-w‑sXZ!yJ
[,P j0
    
return (a%2>0)?"":"";  EETOP專業博客---電子工程師自己的家園~,i"V:k-EQ  EETOP專業博客---電子工程師自己的家園Motp#vO"q)F
}

 

  上面的例子就是標準的內聯函數的用法,使用inline修飾帶來的好處我們表面看不出來,其實在內部的工作就是在每個for循環的內部所有調用dbtest(i)的地方都換成了(i%2>0)?"":""這樣就避免了頻繁調用函數對棧內存重複開闢所帶來的消耗。

  說到這裏很多人可能會問,既然inline這麼好,還不如把所謂的函數都聲明成inline,嗯,這個問題是要注意的,inline的使用是有所限制的,inline只適合函數體內代碼簡單的函數使用,不能包含複雜的結構控制語句例如while switch,並且不能內聯函數本身不能是直接遞歸函數(自己內部還調用自己的函數)

  說到這裏我們不得不說一下在c語言中廣泛被使用的#define語句,是的define的確也可以做到inline的這些工作,但是define是會產生副作用的,尤其是不同類型參數所導致的錯誤,由此可見inline有更強的約束性和能夠讓編譯器檢查出更多錯誤的特性,在c++中是不推薦使用define的。參考http://wenku.it168.com/d_000069212.shtml

 

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