在嵌入式軟件編程中深入理解關(guān)鍵字
③位于模塊內(nèi)的靜態(tài)函數(shù)只能被此模塊內(nèi)的其他函數(shù)調(diào)用。也就是說,這個函數(shù)的作用域為聲明所在的模塊。本文引用地址:http://www.ex-cimer.com/article/152278.htm
為了清楚地理解static的3種用法,必須首先了解C語言中每個標(biāo)識符都具有的作用域、鏈接和存儲持續(xù)期等特性的含義。在ISO C99標(biāo)準(zhǔn)中,其定義如下:
①對象的作用域指的是它僅在程序的某個區(qū)域中是可見的(即可以使用)。常見的作用域有文件作用域和塊作用域。
②對象的存儲持續(xù)期決定對象的生命周期,即在程序執(zhí)行某段區(qū)間中為對象保留存儲區(qū)。有兩種類型的存儲持續(xù)期:靜態(tài)的和自動的。靜態(tài)存儲持續(xù)期的對象的生命周期為程序執(zhí)行的全過程,它的值在程序啟動前僅初始化一次。
③鏈接指的是在不同作用域中聲明的或者同一個作用域中多次聲明的標(biāo)識符可以引用相同的對象或函數(shù)。有3種類型的鏈接:外部、內(nèi)部和無。在情況②和③中,static分別用來修飾全局變量glob-al和函數(shù)foo,改變它們的鏈接特性,使它們具有內(nèi)部鏈接。也就是說,只有在定義它們的翻譯單元或者文件內(nèi)才能使用它們,這對于創(chuàng)建模塊化的軟件非常重要。
與static相反,extern修飾的對象或函數(shù)具有外部鏈接。對于那些暴露給外部使用的接口函數(shù)應(yīng)該使用ex-tern限定,那些非接口函數(shù),例如工具函數(shù)或與實現(xiàn)細(xì)節(jié)相關(guān)的函數(shù),則應(yīng)該顯式地使用static限定。這是因為如果函數(shù)聲明不帶任何存儲類說明符,那么它具有外部鏈接就好像使用了extern一樣。
在情況①中,static用來修飾局部變量local,將local的存儲持續(xù)期由自動的改變?yōu)殪o態(tài)的,這樣在foo函數(shù)的多次調(diào)用間會為其保留值。注意作用域、鏈接和存儲持續(xù)期特性之間是正交的。例如在情況①中,雖然變量local的存儲持續(xù)期變成靜態(tài)的,但是它的作用域仍然是塊作用域。
3 volatile
volatile關(guān)鍵字用來聲明這樣的對象,它們的值可能由于程序控制之外的事件而被潛在改變。volatile強制編譯器不會對其所限定的對象進行任何優(yōu)化,每次讀寫都必須訪問實際的存儲器而不能使用寄存器中的副本。在實踐中,它大量的用來描述一個對應(yīng)于內(nèi)存映射的輸入/輸出端口,例如飛利浦公司LPC21xx系列ARM處理器的向量地址寄存器定義為:
#define VICVectAddr (*((volatile unsigned long*)0xFFFFF030))
其次,中斷服務(wù)例程中使用的非自動變量或者多線程應(yīng)用程序中多個任務(wù)共享的變量也必須使用volatile進行限定。例如在下面的示例中,如果沒有使用volatile限定g_Flag變量,編譯器看到在foo函數(shù)中并沒有修改g_Flag,可能只執(zhí)行一次g_Flag讀操作并將g_Flag的值緩存在寄存器中,以后每次g_Flag讀操作都使用寄存器中的緩存值而不進行存儲器訪問,導(dǎo)致some_action函數(shù)永遠無法執(zhí)行。
4 Dacked
在嵌入式軟件編程中,經(jīng)常需要精確控制結(jié)構(gòu)體在內(nèi)存中的布局和訪問非自然對齊的數(shù)據(jù),但是C語言標(biāo)準(zhǔn)中并沒有統(tǒng)一的規(guī)定而是留給編譯器廠商自行處理。在ARM C編譯器中,使用__packed關(guān)鍵字將任何類型的對齊設(shè)置為1字節(jié)。在實踐中,__packed主要有兩個功能:其一,當(dāng)它修飾指針時,表示此指針指向的地址是非自然對齊的,編譯器會生成特殊的代碼以確保獲得正確的結(jié)果;其二,當(dāng)它修飾結(jié)構(gòu)體、聯(lián)合或它們中的域時,可以用來創(chuàng)建沒有填充的結(jié)構(gòu)。
評論