繼續內存優化——一臉懵逼

若是說以前的優化部分,數據變量和全局局部變量已經讓人頭大,那接下來的部分確定會讓各位感覺到迎面而來的清新氣息。緩存

指針 / Pointers

若是可能,咱們應該使用結構體的引用做爲參數,也就是結構體的指針,不然,整個結構體就會被壓入堆棧,而後傳遞,這會下降速度。程序適用值傳遞可能須要幾K字節,而一個簡單的指針也能夠達到一樣的目的,只須要幾個字節就能夠了。 若是在函數內部不會改變結構體的內容,那麼就應該將參數聲明爲const型的指針。舉個例子:函數

void print_data_of_a_structure (const Thestruct  *data_pointer)
{
     ...printf contents of the structure...
}

這個例子代碼告知編譯器在函數內部不會改變外部結構體的內容,訪問他們的時候,不須要重讀。還能夠確保編譯器捕捉任何修改這個只讀結構體的代碼,給結構體以額外的保護。優化

指針鏈 / Pointer chains

指針鏈常常被用來訪問結構體的信息,好比,下面的這段常見的代碼:lua

typedef struct { int x, y, z; } Point3;
typedef struct { Point3 *pos, *direction; } Object;
void InitPos1(Object *p)
{
    p->pos->x = 0;
    p->pos->y = 0;
    p->pos->z = 0;
}

代碼中,處理器在每次賦值操做的時候都要從新裝載p->pos,由於編譯器不知道p->pos->x不是p->pos的別名。更好的辦法是將p->pos緩存成一個局部變量,以下:spa

void InitPos2(Object *p)
{ 
    Point3 *pos = p->pos;
    pos->x = 0; 
    pos->y = 0;
    pos->z = 0;
}

另外一個可能的方法是將Point3結構體包含在Object結構體中,徹底避免指針的使用。指針

條件的執行 / Conditional Execution

條件執行主要用在if語句中,同時也會用到由關係運算(<,==,>等)或bool運算(&&, !等)組成的複雜的表達式。儘量的保持if和else語句的簡單是有好處的,這樣才能很好的條件化。關係表達式應該被分紅包含類似條件的若干塊。 下面的例子演示了編譯器如何使用條件執行:code

int g(int a, int b, int c, int d)
{
    if(a > 0 && b > 0 && c < 0 && d < 0)  //分組化的條件被捆綁在一塊兒
        return a + b + c + d;
    return -1;
}

條件被分組,便以其可以條件化他們。get

Boolean表達式和範圍檢查 / Boolean Expressions & Range checking

有一種常見的boolean表達式被用來檢查是否一個變量取值在某個特定的範圍內,比方說,檢查一個點是否在一個窗口內。編譯器

bool PointInRectangelArea (Point p, Rectangle *r)
{
    return (p.x >= r->xmin && p.x < r->xmax && p.y >= r->ymin && p.y < r->ymax);
}

這裏還有一個更快的方法:把(x >= min && x < max) 轉換成 (unsigned)(x-min) < (max-min). 尤爲是min爲0時,更爲有效。下面是優化後的代碼:數學

bool PointInRectangelArea (Point p, Rectangle *r)
{
    return ((unsigned) (p.x - r->xmin) < r->xmax && (unsigned) (p.y - r->ymin) < r->ymax);
}

Boolean表達式&與零的比較 / Boolean Expressions & Compares with zero 在比較(CMP)指令後,相應的處理器標誌位就會被設置。這些標誌位也能夠被其餘的指令設置,諸如MOV, ADD, AND, MUL, 也就是基本的數學和邏輯運算指令(數據處理指令)。

假如一條數據處理指令要設置這些標誌位,那麼N和Z標誌位的設置方法跟把數字和零比較的設置方法是同樣的。N標誌位表示結果是否是負數,Z標誌位表示結果是否是零。

在C語言中,處理器中的N和Z標誌位對應的有符號數的關係運算符是x < 0, x >= 0, x == 0, x != 0,無符號數對應的是x == 0, x != 0 (or x > 0)。

C語言中,每用到一個關係運算符,編譯器就會產生一個比較指令。若是關係運算符是上面的其中一個,在數據處理指令緊跟比較指令的狀況下,編譯器就會將比較指令優化掉。好比:

int aFunction(int x, int y)
{
    if (x + y < 0)
        return 1;
    else
        return 0;
}

這樣作,會在關鍵循環中節省比較指令,使代碼長度減小,效率增長。C語言中沒有借位(carry)標誌位和溢出(overflow)標誌位的概念,因此若是不使用內嵌彙編語言,要訪問C和V標誌位是不可能的。儘管如此,編譯器支持借位標誌位(無符號數溢出),比方說:

int sum(int x, int y)
{
     int res;
     res = x + y;
     if ((unsigned) res < (unsigned) x) // carry set?  //
        res++;
     return res;
}

惰性評估計算 / Lazy Evaluation Exploitation

在相似與這樣的 if(a>10 && b=4) 語句中, 確保AND表達式的第一部分最有可能爲false, 結果第二部分極有可能不被執行.

用switch() 代替if...else...,在條件選擇比較多的狀況下,能夠用if…else…else…,像這樣:

if( val == 1)
    dostuff1();
else if (val == 2)
    dostuff2();
else if (val == 3)
    dostuff3();

使用switch能夠更快:

switch( val )
{
    case 1: dostuff1(); break;
    case 2: dostuff2(); break;
    case 3: dostuff3(); break;
}

在if語句中,即便是最後一個條件成立,也要先判斷全部前面的條件是否成立。Switch語句可以去除這些額外的工做。若是你不得不使用if…else,那就把最可能的成立的條件放在前面。

二分分解 / Binary Breakdown

把判斷條件作成二進制的風格,好比,不要使用下面的列表:

if(a == 1) { 
    } else if(a == 2) { 
    } else if(a == 3) { 
    } else if(a == 4) { 
    } else if(a == 5) { 
    } else if(a == 6) { 
    } else if(a == 7) { 
    } else if(a == 8) { 
    }
}

而採用:

if(a <= 4) { 
    if(a == 1) { 
    } else if(a == 2) { 
    } else if(a == 3) { 
    } else if(a == 4) { 
    } 
} else { 
    if(a == 5) { 
    } else if(a == 6) { 
    } else if(a == 7) { 
    } else if(a == 8) { 
    } 
}

甚至:

if(a <= 4) { 
    if(a <= 2) { 
        if(a == 1) { 
                /* a is 1 */ 
        } else { 
                /* a must be 2 */ 
        } 
    } else { 
        if(a == 3) { 
                /* a is 3 */ 
        } else { 
                /* a must be 4 */ 
        } 
    } 
} else { 
    if(a <= 6) { 
        if(a == 5) { 
                /* a is 5 */ 
        } else { 
                /* a must be 6 */ 
        } 
    } else { 
        if(a == 7) { 
                /* a is 7 */ 
        } else { 
                /* a must be 8 */ 
        } 
    } 
}

慢速、低效:

c = getch();
switch(c){
    case 'A': {
        do something;  
        break;  
    } 
    case 'H': {
        do something;
        break;
    }  
    case 'Z': { 
        do something; 
        break; 
    }
}

快速、高效:

c = getch();
switch(c) {
    case 0: {
        do something;
        break;
    }  
    case 1: {
        do something; 
        break;
    } 
    case 2: {
        do something; 
        break; 
    }
}

以上是兩個case語句之間的比較

惰性評估和二分分解是小編內心揮不去的痛啊!!不要放棄,共同進步,還請持續關注更新,更多幹貨和資料請直接聯繫我,也能夠加羣710520381,邀請碼:柳貓,歡迎你們共同討論

相關文章
相關標籤/搜索