C語言

當前位置 /首頁/計算機/C語言/列表

嵌入式C語言程式設計小知識總結

C語言的設計目標是提供一種能以簡易的方式編譯、處理低階儲存器、產生少量的機器碼以及不需要任何執行環境支援便能執行的程式設計語言。那麼式C語言程式設計小知識都有哪些呢?以下僅供參考!

嵌入式C語言程式設計小知識總結

具體如下:

1. 流水線被指令填滿時才能發揮最大效能,即每時鐘週期完成一條指令的執行(僅指單週期指令)。如果程式發生跳轉,流水線會被清空,這將需要幾個時鐘才能使流水線再次填滿。因此,儘量少的使用跳轉指令可以提高程式執行效率,解決發案就是儘量使用指令的“條件執行”功能。

2. 在LPC2200系列中:

可以通過過下面的程式延遲10毫秒:

for(i=0;i<200;i++)

{

for(j=0;j<200;j++);

}

3. 同過下面語句將一個16位的變數放在兩個8位的變數中。

//IP資料報總長度高位元組

IpHeadUint8[10]=(IpHead.e_&0xff00)>>8;

//IP資料報總長度低位元組

IpHeadUint8[11]=IpHead.e_&0x00ff;

4. 在對全部陣列元素賦初值時,可以不指定陣列長度。

eg;inta[]={1,2,3,4,5};

但如果當輸出第a[5]以上的元素時,系統回輸出隨機數值,所以使用此方法時,不能使用超過初始值元素以上的元素。

5. 由於ADS先天性的對printf不支援;因此不便於我們除錯,可以利用串列埠輸出來代替printf來除錯。

6. 用或運算,可使某位置為1,其它位不變

eg: PINSEL0 |= 0x00000005; //設定串列埠引腳

使第0位和第二位置一,其他位不變。

7. 函式指標

1> C語言中函式名直接對應於函式生成的指令程式碼在記憶體中的地址,因此函式名可以直接賦給指向函式的指標

2> 呼叫函式實際上等同於“呼叫指令+引數傳遞處理+迴歸位置入棧”,本質上最核心的操作是將函式生成的目的碼的首地址賦給CPU的PC暫存器。

3> 因為函式呼叫的本質是跳轉到某一個地址單元的code去執行,所以可以“呼叫一個根本就不存在在函式實體

4> int (*p)();定義p是一個指向函式的指標變數,次函式返回帶回整型的返回值。*P兩側的括號不能省略,表示p先於*結合,是指標變數,然後再與後面的()結合,表示此指標指向函式。

區別:int *p()表示這個函式的返回值是指向整型變數的指標。

說明:

(1) 指向函式的指標變數的一般定義形式為:

資料型別 (*指標變數名)();

1> 此處的“資料型別”是指函式返回值的型別

(2) 返回指標值的函式:

型別名 *函式名(引數表)

eg: int * func(int x,int y)

func是函式名,呼叫它以後能返回一個指向整型資料的指標。x,y是func的形參。

區別方法:

a.從右往左找第一個括號,括號裡面的是函式的.形參。

b.括號外面的第一個識別符號是函式的名字,函式前面的表示函式的返回數值。

8. 陣列指標

1>int (*p)[4]

表示*p有4個元素,每個元素為整型。也就是p所指的物件有4個整型元素的陣列,既P是行指標。

2> 指標陣列

一個數組,其元素均為指標型別資料,稱為指標陣列;即指標陣列中的每一個元素都相當於一個指標變數。

一維指標陣列的定義形式為:

型別名 *陣列名[陣列長度]

eg:int *p[4]:

作用:它用於指向若干個字串,使字串處理更加方便靈活。適用於一個二維字串陣列,其中每一行的字元陣列的長度各不相同

eg:char * name[]={“Follow me”,”BASIC”,”GreatWall”};

9. 結構體

1> 可以用結構體變數做實參。但是用結構體變數作實參時,採取的是“值傳遞”的方式,將結構體變數所佔的記憶體單元的內容全部順序遞給形參。形參也必須是同類型的結構體變數。

eg:pint(su);//注在此處su為結構體

注:這種傳遞方式在空間和時間上開銷較大,如果結構體的規模較大時,開銷是很可觀的。

2> 用直向結構體變數(或陣列)的指標作實參,將結構體變數(或陣列)的地址傳給形參

eg:print(&su);//注在此處su為結構體

10. 共用體

1> 共用體把幾種不同資料型別的變數存放在同一塊記憶體裡。公用體中的變數共享同一塊記憶體。

2> 定義公用體型別變數的一般形式為:

union 共用體名

{

成員列表;

}變數列表;

3>在共用體中同一塊記憶體可以用來存放幾種不同型別的資料,但在某一時刻只能在其中存放一個成員變數。共用體變數中起作用的成員是最後一次存入的資料。

eg: union data

{

int i;

char c;

double d;

};

union data a;

共用體變數a中的成員i,c,d三個變數在記憶體中從同一個地址開始儲存。如進行如下賦值:

a.i = 100;

a.c = ‘A’;

那麼此時共用體變數a中的成員i已經沒有值了,因為儲存該值的記憶體現在已經被用來儲存成員c的值了。

3> 共用體變數的長度取決於其成員的最大長度:

說明:

結構體變數所佔記憶體的長度是各個成員的總和,每個成員分別佔有自己的儲存空間。共用體變數所佔記憶體的長度是其最長成員的長度。當然,編譯器出於提高訪問效率的目的,在編譯分配儲存空間時往往要進行對齊操作。

對齊操作以最大基本型別為準。即以最大基本型別為基本單元。若按實際算下的長度不是基本單元的整數倍,則其實際長度應該是基本單元的整數倍。

(在TurboC中不進行對齊,在Linux中進行對齊)

11. CPU字長與儲存器位寬不一致處理

例如:使用共用體來解決這一衝突:

union send_temp{

uint16 words;

uint8 bytes[2];

}send_buff;

eg:send_s[0]=a;//此處a 是8位

send_s[1]=b;//此處 b 是8位;

此時就將8位字拼成了16位字儲存了。

傳送時send(send_s)就可以每次傳送一個16位的資料了。

12. C語言符號優先順序:

1>複合賦值運算子號:

a+=3*5;

等價於a=a+(3*5);

13.一個常見的除錯策略是把一些printf函式的呼叫散佈於程式中,確定錯誤出現的具體位置。但是,這些函式呼叫的輸出結果被寫入到緩衝區中,並不立即顯示於螢幕上。事實上,如果程式失敗,緩衝輸去可能不會被實際寫入,因此得到的錯誤位置就是錯誤的。解決的方法是在每個用於除錯的printf函式之後立即呼叫fflush函式即可得到。

printf(“something or other”);

fflush(stdout);

14.關鍵字volatile的用法

volatile變數可能用於如下幾種情況:

1>裝置的硬體暫存器(如:狀態暫存器)

2>一箇中斷服務子程式中會訪問到的全域性變數

3>多執行緒應用中被幾個任務共享的變數。

15.關鍵字register的用法:

當對一個變數頻繁被讀寫時,需要反覆訪問記憶體,從而花費大量的存取時間。為此,C語言提供了一種變數,即暫存器變數。這種變數存放在CPU的暫存器中,使用時,不需要訪問記憶體,而直接從暫存器中讀寫,從而提高效率。暫存器變數的說明符是register。對於迴圈次數較多的迴圈控制變數及迴圈體內反覆使用的變數均可定義為暫存器變數,而迴圈計數是應用暫存器變數的最好候選者。

(1) 只有區域性自動變數和形參才可以定義為暫存器變數。因為暫存器變數屬於動態儲存方式,凡需要採用靜態儲存方式的量都不能定義為暫存器變數,包括:模組間全域性變數、模組內全域性變數、區域性static變數;

(2) register是一個"建議"型關鍵字,意指程式建議該變數放在暫存器中,但最終該變數可能因為條件不滿足並未成為暫存器變數,而是被放在了儲存器中,但編譯器中並不報錯(在C++語言中有另一個"建議"型關鍵字:inline)。

16.對於程式程式碼,已經被燒錄在FLASH或ROM中,我們可以讓CPU直接從其中讀取程式碼執行,但通常這不是一個好辦法,我們最好在系統啟動後將FLASH或ROM中的目的碼拷貝入RAM中後再執行以提高取指令速度;

CPU對各種儲存器的訪問速度,基本上是:

CPU內部RAM > 外部同步RAM > 外部非同步RAM > FLASH/ROM

17. 巨集定義

在C語言中,巨集是產生內嵌程式碼的唯一方法。對於嵌入式系統而言,為了能達到效能要求,巨集是一種很好的代替函式的方法。

1>巨集定義“像”函式;

2>巨集定義不是函式,因而需要括上所有“引數”;

3>巨集定義可能產生副作用。因而不要給巨集定義傳入有副作用的"引數"。