1. 程式人生 > >C語言提高程式碼效率的幾種方法

C語言提高程式碼效率的幾種方法

一段完美的程式碼不僅在於找到一個給定的問題的解決方案,但在它的簡單性,有效性,緊湊性和效率(記憶體)。設計的程式碼比實際執行更難。因此,每一個程式設計師當用C語言開發時,都應該保持這些基本的東西在頭腦中。本文向你介紹規範你的C程式碼的幾種方法。

1、在可能的情況下使用typedef替代macro.當然有時候你無法避免macro,但是typedef更好。

typedef  int*  INT_PTR; INT_PTR  a ,b;

# define INT_PTR  int*; INT_PTR  a ,b;

在這個巨集定義中,a是一個指向整數的指標,而b是隻有一個整數宣告。使用typedef a和b都是整數的指標。

2、在一個邏輯條件語句中常數項永遠在左側。

int  x = 4; if (x = 1)

{

 x = x + 2;

printf("%d",x);// Output is 3  }

int  x = 4;

if (1 = x)

{

x = x + 2;

printf("%d",x); // Compilation error

}

使用"="賦值運算子,替代"=="相等運算子,這是個常見的輸入錯誤。常數項放在左側,將產生一個編譯時錯誤,讓你輕鬆捕獲你的錯誤。注:"="是賦值運算子。b = 1會設定變數b等於值1。"=="相等運算子。如果左側等於右側,返回true,否則返回false。

3、確保宣告和定義是靜態的,除非您希望從不同的檔案中呼叫該函式。

在同一檔案函式對其他函式可見,才稱之為靜態函式。它限制其他訪問內部函式,如果我們希望從外界隱藏該函式。現在我們並不需要為內部函式建立標頭檔案,其他看不到該函式。靜態宣告一個函式的優點包括:

(1)兩個或兩個以上具有相同名稱的靜態函式,可用於在不同的檔案。

(2)編譯消耗減少,因為沒有外部符號處理。

4、節約記憶體(記憶體對齊和填充的概念)

struct  {  char c; int i; 

short s;}str_1;  

struct  { char c; shorts; inti;}str_2; 

假設一個字元需要1個位元組,short佔用2個位元組和int需要4位元組的記憶體。起初,我們會認為上面定義的結構是相同的,因此佔據相同數量的記憶體。然而,而str_1佔用12個位元組,第二個結構只需要8個位元組?這怎麼可能呢?  

請注意,在第一個結構,3個不同的4個位元組被分配到三種資料型別,而在第二個結構的前4個自己char和short可以被採用,int可以採納在第二個的4個位元組邊界(一共8個位元組)

5、使用無符號整數,而不是整數的,如果你知道的值將永遠是否定的。

有些處理器可以處理無符號的整數,比有符號整數的運算速度要快。(這也是很好的實踐,幫助self-documenting程式碼)

6、switch-case語句。在程式中經常會使用switch-case語句,每一個由機器語言實現的測試和跳轉僅僅是為了決定下一步要做什麼,就浪費了處理器時間。為了提高速度,可以把具體的情況按照它們發生的相對頻率排序。即把最可能發生的情況放在第一,最不可能發生的情況放在最後,這樣會減少平均的程式碼執行時間。

當switch語句中的case標號很多時,為了減少比較的次數,明智的做法是把大switch語句轉為巢狀switch語句。把發生頻率高的case標號放在一個switch語句中,並且是巢狀switch語句的最外層,發生相對頻率相對低的case標號放在另一個switch語句中。比如,下面的程式段把相對發生頻率低的情況放在預設的case標號內。

pMsg=ReceiveMessage();

switch (pMsg->type)

{

case FREQUENT_MSG1:

handleFrequentMsg();

break;

case FREQUENT_MSG2:

handleFrequentMsg2();

break;

......

case FREQUENT_MSGn:

handleFrequentMsgn();

break;

default: //巢狀部分用來處理不經常發生的訊息

switch (pMsg->type)

{

case INFREQUENT_MSG1:

handleInfrequentMsg1();

break;

case INFREQUENT_MSG2:

handleInfrequentMsg2();

break;

......

case INFREQUENT_MSGm:

handleInfrequentMsgm();

break;

}

}

如果switch中每一種情況下都有很多的工作要做,那麼把整個switch語句用一個指向函式指標的表來替換會更加有效,比如下面的switch語句,有三種情況:

enum MsgType{Msg1, Msg2, Msg3}

switch (ReceiveMessage())

{

case Msg1;......

case Msg2;.....

case Msg3;.....

}

為了提高執行速度,用下面這段程式碼來替換這個上面的switch語句

/*準備工作*/

int handleMsg1(void);

int handleMsg2(void);

int handleMsg3(void);

/*建立一個函式指標陣列*/ 

int (*MsgFunction [])()={handleMsg1, handleMsg2, handleMsg3};

/*用下面這行更有效的程式碼來替換switch語句*/

status=MsgFunction[ReceiveMessage()]();

7、全域性變數。使用全域性變數比向函式傳遞引數更加有效率,這樣做去除了函式呼叫前引數入棧和函式完成後引數出棧的需要。當然,使用全域性變數會對程式有一些負作用。使用全域性變數比函式傳遞引數更加有效率。這樣做去除了函式呼叫引數入棧和函式完成後引數出棧所需要的時間。然而決定使用全域性變數會影響程式的模組化和重入,故要慎重使用。

8、嵌入式系統程式設計應避免使用標準庫例程,因為很多大的庫例程設法處理所有可能的情況,所以佔用了龐大的記憶體空間,因而應儘可能地減少使用標準庫例程。

9、Inline函式。在C++中,關鍵字Inline可以被加入到任何函式的宣告中。這個關鍵字請求編譯器用函式內部的程式碼替換所有對於指出的函式的呼叫。這樣做在兩個方面快於函式呼叫。這樣做在兩個方面快於函式呼叫:第一,省去了呼叫指令需要的執行時間;第二,省去了傳遞變元和傳遞過程需要的時間。但是使用這種方法在優化程式速度的同時,程式長度變大了,因此需要更多的ROM。使用這種優化在Inline函式頻繁呼叫並且只包含幾行程式碼的時候是最有效的。

10、用指標代替陣列。在許多種情況下,可以用指標運算代替陣列索引,這樣做常常能產生又快又短的程式碼。與陣列索引相比,指標一般能使程式碼速度更快,佔用空間更少。使用多維陣列時差異更明顯。下面的程式碼作用是相同的,但是效率不一樣。

陣列索引                     指標運算

For(;;){                         p=array      

A=array[t++];              for(;;){

                                     a=*(p++); 

......                               ......  

}

指標方法的優點是,array的地址每次裝入地址p後,在每次迴圈中只需對p增量操作。在陣列索引方法中,每次迴圈中都必須進行基於t值求陣列下標的複雜運算。

11、不定義不使用的返回值。function函式定義並不知道函式返回值是否被使用,假如返回值從來不會被用到,應該使用void來明確宣告函式不返回任何值。

12、手動編寫彙編。在嵌入式軟體開發中,一些軟體模組最好用匯編語言來寫,這可以使程式更加有效。雖然C/C++編譯器對程式碼進行了優化,但是適當的使用內聯彙編指令可以有效的提高整個系統執行的效率。

13、使用暫存器變數。在宣告區域性變數的時候可以使用register關鍵字。這就使得編譯器把變數放入一個多用途的暫存器中,而不是在堆疊中,合理使用這種方法可以提高執行速度。函式呼叫越是頻繁,越是可能提高程式碼的速度。

14、使用增量和減量操作符。在使用到加一和減一操作時儘量使用增量和減量操作符,因為增量符語句比賦值語句更快,原因在於對大多數CPU來說,對記憶體字的增、減量操作不必明顯地使用取記憶體和寫記憶體的指令,比如下面這條語句:x=x+1;

 模仿大多數微機組合語言為例,產生的程式碼類似於:

move A,x ;把x從記憶體取出存入累加A

add A,1 ;累加器A加1     

store x  ;把新值存回x 

如果使用增量操作符,生成的程式碼下:

incr x ;x加1 

顯然,不用取指令和存指令,增、減量操作執行的速度加快,同時長度也縮短了。

相關推薦

C語言提高程式碼效率方法

一段完美的程式碼不僅在於找到一個給定的問題的解決方案,但在它的簡單性,有效性,緊湊性和效率(記憶體)。設計的程式碼比實際執行更難。因此,每一個程式設計師當用C語言開發時,都應該保持這些基本的東西在頭腦中。本文向你介紹規範你的C程式碼的幾種方法。 1、在可能的情況下使用typ

C#多線程的方法

task start invoke 數組 erl method 並行計算 bsp nbsp 1、Theard2、TheardPool 線程池3、Task 在Theard上做了優化和改進,建議使用 .start();4、Task.Factory.Start(method)

C#線程同步的方法

sso 代碼 services 讀寫 基於 star 代碼段 不能 命名   在網上也看過一些關於線程同步的文章,其實線程同步有好幾種方法,下面我就簡單的做一下歸納。   一、volatile關鍵字   volatile是最簡單的一種同步方法,當然簡單是要付出代價的。它

C#獲取當前路徑的方法

size start orm name uri path ant tom 當前 //1.獲取模塊的完整路徑。 string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileNam

求組合數C(n,m) % mod的方法

演算法一:乘法逆元,在m,n和mod比較小的情況下適用 乘法逆元:(a/b)% mod = a * b^(mod-2),mod為素數   #include<iostream> #include<cstdio> #include<cmath>

歸納一下:C#執行緒同步的方法

 我們在程式設計的時候,有時會使用多執行緒來解決問題,比如你的程式需要在後臺處理一大堆資料,但還要使使用者介面處於可操作狀態;或者你的程式需要訪問一些外部資源如資料庫或網路檔案等。這些情況你都可以建立一個子執行緒去處理,然而,多執行緒不可避免地會帶來一個問題,就是執行緒同步的問題。如果這個問題處理不好,我們就

[轉]C/C++定義全域性變數/常量方法的區別

在討論全域性變數之前我們先要明白幾個基本的概念: 原文章地址:https://www.cnblogs.com/wanghetao/p/4492582.html 1. 編譯單元(模組):     在IDE開發工具大行其道的今天,

C語言 數值交換的三方法

一、程式設計思想 (1)通過建立第三個變數來交換數值; (2)不建立變數,通過加減的方式交換(PS:如果倆個數值過大,則可能會溢位) (3)不建立變數,通過異或操作符交換(最高效簡潔,不會溢位,是1、2的升級) ——異或的思想 將數值以ASCII碼的形式,按二進

C++中輸入字串的方法

轉自http://gwyan.blog.163.com/blog/static/213337092201361734257744/C++中幾個輸入函式的用法和區別(cin、cin.get()、cin.getline()、getline()、gets()、getchar()))

C++中時間延遲的方法

方法七:對於精確度要求更高的定時操作,則應該使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函式。這兩個函式是VC提供的僅供Windows 95及其後續版本使用的精確時間函式,並要求計算機從硬體上支援精確定時器。如示例工程中的Timer7、Ti

C#_CombolBox新增資料的方法

方法一:檢視新增 方法二:利用陣列新增 string[] comValue = new string[] {"北京","上海","天津","重慶","廣東","廣西","湖南","湖北" };

C語言巨集替換的用法 【轉載】

①簡單巨集替換             #defind   Pi   3.14159     或           #ifndef   __THIS_FILE__           #define   __THIS_FILE__     //   用於防止重複包含檔案               ……  

C++定義全域性變數/常量方法的區別

1、extern和static不能同時修飾一個變數;其次,static修飾的全域性變數宣告與定義同時進行,也就是說當你在標頭檔案中使用static聲明瞭全域性變數後,它也同時被定義了;最後,static修飾全域性變數的作

C#執行緒同步的方法

Code public void Function() {object lockThis = new object (); lock (lockThis){// Access thread-sensitive resources. }}

c#匯出Excel檔案的方法

using System; using System.Collections.Generic; using System.Text; using System.Data; using System.Windows.Forms; using System.Re

C++讀取配置檔案的方法

ini檔案的話讀取更方便點。C++中有寫ini檔案和讀ini檔案的函式(應該是VC環境提供的,標準C++沒有。)windows下就直接用函式讀取ini檔案 看的你配置檔案是什麼型別了,如果是xml檔案的話,可以用TinyXML解析器去解析,看這裡:http://www.c

C語言中字串的定義方式和有沒有’\0‘

( 主要解決 什麼時候是 “abcd\0” 什麼時候是 “abcd” 的問題 ) 幾種常用方式: 1.char* str = “abcd”; 2.char str[] = { “abcd” }; 3.char str[] = { ‘a’, ‘b’, ‘c

C#Winform開啟窗體的方法、注意事項的總結

C#Winform開啟窗體的幾種方法、注意事項的解決 一、開啟MDI子窗體,且允許重複開啟 FrmMytest frmMytest = new FrmMytest(); frmMytest.MdiParent = this; frmMytest.Show();
 二、開啟

C/C++定義全域性變數/常量方法的…

在討論全域性變數之前我們先要明白幾個基本的概念: 1. 編譯單元(模組):     在IDE開發工具大行其道的今天,對於編譯的一些概念很多人已經不再清楚了,很多程式設計師最怕的就是處理連線錯誤(LINK ERROR), 因為它不像編譯錯誤那樣可以給出你程式錯誤的具體位置,你常常對這種錯誤感到懊惱,但是如果你

C語言求素數的兩方法

1,判斷n是否能被1~n-1整除 #include<stdio.h> int main() { int i, n; scanf("%d", &n); for