嵌入式C語言優化小技巧

2021-09-11 07:06:02 字數 4280 閱讀 2544

嵌入式系統是指完成一種或幾種特定功能的計算機系統,具有自動化程度高,響應速度快等優點,目前已廣泛應用於消費電子,工業控制等領域.嵌入式系統受其使用的硬體以及執行環境的限制,非常注重**的時間和空間效率,因此選擇一種合適的開發語言十分重要.目前,在嵌入式系統開發中可使用的語言很多,其中 c語言應用得最廣泛.雖然用 c 語言程式設計具有許多優點,但基於嵌入式系統的c語言和標準 c語言又有很大區別.接下來我結合嵌入式系統的特點和自己的一些積累,討論在程式設計中**優化的一些小技巧.

作為一種結構化程式設計語言,c 語言兼顧多種高階語言的特點,具有很強的功能性和可移植性.但在嵌入式系統開發中,出於對低價產品的需求,系統的計算能力和儲存容量都非常有限,因此如何利用好這些資源就顯得十分重要.開發人員應注意嵌入式 c語言和標準 c 語言的區別,減少生成**長度,提高程式執行效率,在程式設計中對**進行優化.

現在的 c 編譯器會自動對**進行優化,但這些優化是對執行速度和**長度的平衡.如果要獲得更小且執行效率更高的**,需要程式設計師手工對**進行優化.

不同的資料型別所生成的機器**長度相差很多,變數型別選取的範圍越小執行速度越快,占用的記憶體越少.能夠使用字元型(char)定義的變數,就不要使用整型(int)變數來定義;能夠使用整型變數定義的變數就不要用長整型(long int),能不使用浮點型(float)變數就不要使用浮點型變數.相同型別的資料型別,有無符號對機器**長度也有影響.因此我們應按照實際需要合理的選用資料型別.當然,在定義變數後不要超過變數的作用範圍,如果超過變數的範圍賦值,c編譯器並不報錯,但程式執行結果卻錯了,而且這樣的錯誤很難發現.

5 演算法優化

演算法優化指對程式時空複雜度的優化:在 pc 機上進行程式設計時一般不必過多關注程式**的長短,只需考慮功能的實現,但嵌入式系統就必須考慮系統的硬體資源,在程式設計時,應盡量採用生成**短的演算法,在不影響程式功能實現的情況下優化演算法.

在 c程式中使用巨集**可以提高程式的執行效率.巨集**本身不是函式.但使用起來像函式.函式呼叫要使用系統的棧來儲存資料,同時 cpu 在函式呼叫時需要儲存和恢復當前的現場,進行進棧和出棧操作,所以函式呼叫也需要 cpu時間.而巨集定義就沒有這個問題:巨集定義僅僅作為預先寫好的**嵌入到當前程式中,不產生函式呼叫,所占用的僅僅是一些空間,省去了引數壓棧,生成組合語言的 call 呼叫,返回引數,執行 return等過程,從而提高了程式的執行速度.雖然巨集破壞了程式的可讀性,使排錯更加麻煩,但對於嵌入式系統,為了達到要求的效能,嵌入**常常是必須的做法.

此外,我們還要避免不必要的函式呼叫,請看下面的**:

void str_print( char *str )

}void str_print1 ( char *str )

}請注意,這兩個函式的功能相似.然而,第乙個函式呼叫strlen函式多次,而第二個函式只呼叫函式strlen一次.因此第二個函式效能明顯比第乙個好.

程式中對時間要求苛刻的部分可以用內嵌彙編來重寫,以帶來速度上的顯著提高.但是,開發和測試彙編**是一件辛苦的工作,它將花費更長的時間,因而要慎重選擇要用彙編的部分.在程式中,存在乙個80-20原則,即20%的程式消耗了80%的執行時間,因而我們要改進效率,最主要是考慮改進那20%的**.

8 提高迴圈語言的效率

在 c 語言中迴圈語句使用頻繁,提高迴圈體效率的基本辦法就是降低迴圈體的複雜性:

(1)在多重迴圈中,應將最長的迴圈放在最內層,最短的迴圈放在最外層.這樣可以減少 cpu跨切迴圈的次數.如例 1-1 的效率比 1-2 的效率要低:

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

} // 例子 1-1

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

} // 例子 1-2

例 1-1長迴圈在外層,效率低;例 1-2長迴圈在內層,效率高.

(2) 如果迴圈體內有邏輯判斷,並且迴圈次數大,應把迴圈判斷移到迴圈體外.如例 2-1比例 2-2 多執行了 k-1 次判斷,而且由於前者頻繁進行判斷,打斷了迴圈"流水線"作業,使得編譯器不能對迴圈進行優化處理,降低了效率.

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

// 例子 2-1 程式簡潔但效率低

if (條件)

else 

// 例子 2-2 程式部簡潔但效率高

switch 語句是 c 語言中常用的選擇語句, 在編譯時會產生if- else- if 巢狀**,並按照順序進行比較,發現匹配時,就跳轉到滿足條件的語句執行.

當 switch 語句中的 case 標號很多時,為了減少比較的次數,可以把發生頻率相對高的條件放到第一位或者把整個 switch 語句轉化巢狀 switch 語句.把發生頻率高的 case 標號放在最外層的 switch 語句中,發生相對頻率相對低的 case 標號放在另外的 switch 語句中.如例 3 中,把發生率高的case 標號放在外層的 switch 語句中,把發生頻率低的放在預設

的(default)內層 switch 語句中.

switch (表示式)

}例子3 使用巢狀switch語句提高程式執行效率.

使用 c語言標準庫可以加快開發進度,但由於標準庫需要設法處理使用者所有可能遇到的情況,所以很多標準庫**很大.比如標準庫中的 sprintf函式非常大.這個龐大的**中有很大一部分用於處理浮點數,如果程式中不需要格式化浮點數值( 如%f),程式設計人員就可以根據實際情況用少量的**實現這個功能.

數學是計算機之母,沒有數學的依據和基礎,就沒有計算機的發展,所以在編寫程式的時候,採用一些數學方法會對程式的執行效率有數量級的提高.有時候這個問題常常被大家忽略, 對於沒有經驗的程式設計師來說更是如此.例如:求 1~100 的和

sum = 100*(100+1)/2; 數學公式. (a1 + an)*n/2

使用c語言的位操作可以減少除法和取模的運算.在電腦程式中資料的位是可以操作的最小資料單位,理論上可以用「位運算」來完成所有的運算和操作.因而,靈活的位操作可以有效地提高程式執行的效率.比如用用位操作區代替除法:比如:128 / 8 ->> 128 >> 3;

優化演算法和資料結構對提高**的效率有很大的幫助.當然有時候時間效率和空間效率是對立的,此時應分析哪個更重要, 做出適當的折中.另外,在進行優化的時候不要片面的追求緊湊的**,因為緊湊的**並不能產生高效率的機器碼.

由於成本限制,嵌入式系統儲存器容量有限.程式中所有的變數,包含的庫函式以及堆疊等都使用有限的記憶體:全域性變數在整個程式範圍內都有效.程式執行完後才會釋放;靜態變數的作用範圍也是整個程式,只有區域性變數中的動態變數在函式執行完後會釋放.因此, 在程式中應盡量使用區域性變數,提高記憶體使用效率.程式中堆的大小受限於所有全域性資料和棧空間都分配後的剩餘量,如果堆太小,程式不能夠在需要的時候分配記憶體.因此在使用 malloc 函式申請記憶體之後一定要用 free 函式進行釋放, 防止記憶體洩露.

在程式設計中,我們常常需要用到無限迴圈,常用的兩種方法是while (1) 和 for (;;).這兩種方法效果完全一樣,但那一種更好呢?然我們看看它們編譯後的**:

編譯前:

while (1);

編譯後:

mov eax,1

test eax,eax

je foo+23h

jmp foo+18h

編譯前:

for (;;);

編譯後:

jmp foo+23h

顯然,for (;;)指令少,不占用暫存器,而且沒有判斷,跳轉,比while (1)好.

考慮fibonacci(斐波那契)問題,fibonacci問題是可以通過簡單的遞迴方法來解決:

int fib ( n )

else 

}注:在這裡,我們考慮fibonacci 系列從1開始,因此,該系列看起來:1,1,2,3,5,8,…

注意:從遞迴樹,我們計算fib(3)函式2次,fib(2)函式3次.這是相同函式的重複計算.如果n非常大,fib函式的效率會比較低.memoization是乙個簡單的技術,可以被用在遞迴,加強計算速度.fibonacci 函式memoization的**如下:

int calc_fib ( int n )

val[ 0 ] = 1;               // value of fib ( 0 ) is set to 1

val[ 1 ] = 1;           // value of fib ( 1 ) is set to 1

return fib( n , val );

}int fib( int n , int* value )

else 

return value[ n ];                // returning the value

}除了程式設計上的技巧外,為提高系統的執行效率,我們通常也需要最大可能地利用各種硬體裝置自身的特點來減小其運轉開銷,例如減小中斷次數,利用dma傳輸方式等.

ARM嵌入式C語言設計小技巧

1 變數定義 先來看下邊的兩處變數定義 char a short b char c int d char a char c short b int d 顯然兩處定義的變數是相同的,不同之處在於定義的順序。看一下他們分別在資料區的布局 pad為無意義的填充空間 a pad b c padd a c b...

嵌入式c語言優化

一.演算法和資料結構優化 1.針對應用的演算法優化,比如,在音訊編譯碼中,用fft實現時頻變換。2.c語言級別的優化,如排序演算法的選擇。3.資料結構的選擇,如果需要隨機訪問,則盡量選擇陣列,如果需要隨機插入刪除,則可以選擇鍊錶。4.盡量用指標代替資料操作,大部分編譯對於指標會生成更小更快的 5.盡...

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

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