初入職軟件工程師的血淚——C語言內存優化

剛剛開始工做就被前輩訓得一塌糊塗,特別是對於優化這一塊沒有一點潛意思,如今不得不從新學習代碼優化。編程

對於優化C代碼有不少有效的指導方針,可是對於完全地瞭解編譯器和你工做的機器依然沒法取代,一般,加快程序的速度也會加大代碼量。這些增長的代碼也會影響一個程序的複雜度和可讀性,這是不可接受的,好比你在一些小型的設備上編程,例如:移動設備、PDA……,這些有着嚴格的內存限制,因而,在優化的座右銘是:寫代碼在內存和速度都應該優化。數組

整型數 / Integers

在咱們知道使用的數不多是負數的時候,應該使用unsigned int取代int,一些處理器處理整數算數運算的時候unsigned int比int快,因而,在一個緊緻的循環裏面定義一個整型變量,最好這樣寫代碼:函數

register unsigned int variable_name;

然而,咱們不能保證編譯器會注意到那個register關鍵字,也有可能,對某種處理器來講,有沒有unsigned是同樣的。這兩個關鍵字並非能夠在全部的編譯器中應用。記住,整形數運算要比浮點數運算快得多,由於處理器能夠直接進行整型數運算,浮點數運算須要依賴於外部的浮點數處理器或者浮點數數學庫。咱們處理小數的時候要精確點些(好比咱們在作一個簡單的統計程序時),要限制結果不能超過100,要儘量晚的把它轉化成浮點數。學習

除法和餘數 / Division and Remainder

在標準的處理器中,根據分子和分母的不一樣,一個32位的除法須要20-140個時鐘週期來執行完成,等於一個固定的時間加上每一個位被除的時間。優化

Time (分子/ 分母) = C0 + C1* log2 (分子/分母)     

= C0 + C1 * (log2 (分子) - log2 (分母)).

如今的ARM處理器須要消耗20+4.3N個時鐘週期,這是一個很是費時的操做,要儘量的避免。在有些狀況下,除法表達式能夠用乘法表達是來重寫。比方說,(a/b)>c能夠寫成a>(cb),條件是咱們已經知道b爲非負數並且bc不會超過整型數的取值範圍。若是咱們可以肯定其中的一個操做數爲unsigned,那麼使用無符號除法將會更好,由於它要比有符號除法快得多。ui

合併除法運算和取餘運算 / Combining division and remainder

在一些狀況下,除法運算和取餘運算都須要用到,在這種狀況下,編譯器會將除法運算和取餘運算合併,由於除法運算老是同時返回商和餘數。若是兩個運算都要用到,咱們能夠將他們寫到一塊兒spa

int func_div_and_mod (int a, int b) { 
     return (a / b) + (a % b);
}

除數是2的冪的除法和取餘 / Division and remainder by powers of two

若是除法運算中的除數是2的冪,咱們對這個除法運算還能夠進一步優化,編譯器會使用移位運算來進行這種除法運算。因此,咱們要儘量調整比例爲2的冪(比方說要用64而不用66)。若是是無符號數,它要比有符號的除法快得多。code

typedef unsigned int uint;
uint div32u (uint a) {
     return a / 32;
}
int div32s (int a) {
     return a / 32;
}

這兩種除法都會避免調用除法函數,另外,無符號的除法要比有符號的除法使用更少的指令。有符號的除法要耗費更多的時間,由於這種除法是使最終結果趨向於零的,而移位則是趨向於負無窮。索引

取模運算的替換 / An alternative for modulo arithmetic

咱們通常使用取餘運算進行取模,不過,有時候使用 if 語句來重寫也是可行的。考慮下面的兩個例子:內存

uint modulo_func1 (uint count)
{
    return (++count % 60);
}
uint modulo_func2 (uint count)
{
    if (++count >= 60)
        count = 0;
    return (count);
}

第二個例子要比第一個更可取,由於由它產生的代碼會更快,注意:這只是在count取值範圍在0 – 59之間的時候才行。

可是咱們可使用以下的代碼(筆者補充)實現等價的功能:

uint modulo_func3 (uint count)
{
    if (++count >= 60)
        count %= 60;
    return (count);
}

使用數組索引 / Using array indices

假設你要依據某個變量的值,設置另外一個變量的取值爲特定的字符,你可能會這樣作:

switch(queue) {
    case 0 :   letter = 'W';
        break;
    case 1 :   letter = 'S';
        break;
    case 2 :   letter = 'U';
        break;
}

或者這樣:

if(queue == 0)
    letter = 'W';
else if ( queue == 1 )
    letter = 'S';
else
    letter = 'U';

有一個簡潔且快速的方式是簡單的將變量的取值作成一個字符串索引,例如:

static char *classes = "WSU";
letter = classes[queue];

數據優化暫時先寫這麼多,請持續關注更新,更多幹貨和資料請直接聯繫我,也能夠加羣710520381,邀請碼:柳貓,歡迎你們共同討論

相關文章
相關標籤/搜索