變量與寄存器程序員
未指定優化選項時,編譯器會將程序中的變量儲存到內存上,程序在執行相關運算時會根據須要裝載到寄存器,當運算結束後再將運算器上的內容移到內存,而後生成目標代碼。算法
但若是指定了優化選項,變量就會盡量地儲存在寄存器上,從而減小訪存時間。數據庫
===============express
變量間的乘法運算編程
和加法運算相同,CPU內部有多個乘法器,它們是爲了同時計算乘法運算而存在的。數組
變量與常量的乘法緩存
當編譯器進行常量乘法計算時,儘量不使用CPU內的乘法計算器,而使用移位結合加法運算。性能優化
···················網絡
當咱們作「2的乘方+1」(即3,5,9等)的乘法運算時,採用CPU中具有的lea(load effective address)指令,也能下降執行成本。好比:函數
將變量與常量5相乘,至關於將寄存器內的值*4+寄存器的值。 注意編譯器在進行計算時可能利用cpu內部全部的計算功能來計算,原本LEA是用於計算地址值的,但這裏卻用於簡化乘法計算。
負數的乘法經過移位運算也能夠代替乘法運算。
=================
除法操做是比乘法更爲耗時的運算。
與乘法運算相同,除以2的乘方時,能夠經過寄存器內數據的移位操做來提升效率。可是對於負數的除法運算還必須另外考慮????
除數不是2的乘方的除法計算
當除數不是2的乘方時,編譯器也可能會進行優化。可是相關計算比較繁瑣,對於有符號數的要轉化爲無符號數進行計算。
利用減法和移位求除數是5的除法運算。
A/5能夠轉化爲先計算A=A>>2; 因爲除4帶來看「偏差」miss=A
單核CPU中一些運算也多是並行的,好比浮點數乘法運算。
儘管許多程序仍是依賴單線程的執行,現代處理器在單核中也提供了很多的並行性。例如:單個CPU能夠同時執行4個浮點數乘,等待4個內存請求並執行一個分支預判。
避免或減小使用本地變量。
本地變量一般都存儲在棧上。不過若是數量比較少,它們能夠存儲在CPU寄存器中。在這種狀況下,函數不但獲得了更快訪問存儲在寄存器中的數據的好處,也避免了初始化一個棧
幀的開銷。
編譯器、中間件篇
操做系統和編譯器的基礎軟件,數據庫軟件、網絡協議棧,擴充文件系統這些軟件叫作中間件。它們捨棄了複雜且原始的計算機操做,將程序員要解決的問題集中起來處理。
輸入輸出操做十分耗時,若是能夠將屢次輸入輸出操做集中起來歸併處理。
有效利用輸入輸出緩衝區很是重要。
將strcpy函數替換爲memcpy函數可以提升效率。
算法
結合數據來調整算法。
4.2 硬件篇--數組和緩存 的有效利用
若存取的數據在內存中是連續的,緩存的做用就能獲得更好發揮。但若是數據在內存中不是連續的,就會發生緩存未命中,從而增長存取時間。
下面經過一個例子來講明如何安排循環來提升緩存利用效率。
矩陣乘法
Cij=sigma(Aik*Bkj)
若是直接將這個式翻譯爲程序的話,結果以下:
for (int i = 0; i < 2; i++){
for (int k = 0; k < 2; k++){
for (int j = 0; j < 3; j++){
//設計循環時,注意到對數組b,當內層循環爲對j的循環時,b[k][j]是連續的,
//同時在內層環中a[i][k]是一個固定值。並且調換順序後,對結果並不產生影響。但計算速度會加快。但這只是理論上的分析,實際上,並無發現快了。反而是慢了。
res[i][j] += a[i][k] * b[k][j];
//有時候爲了提升速度能夠考慮展開內層循環。
}
}
}
4.3 庫函數篇
說到字符串比較,你們通常用的是strcmp函數,它是經過對字符串逐個字符進行比較來實現的,但若是要對比的字符串比較長的話,則執行時間也會比較長,這是個難點。
對於須要處理較長的字符串的狀況,或字符串的問題比較大的狀況,能夠考慮將strcmp函數替換爲memcmp函數以實現高效編程。
分析:strcmp是一個字符一個字符進行比較,而memcmp函數將須要比較的字符串分割成4個字節或8個字節一組的詞爲單位進行對比操做,這樣就節約了時間。但請注意:這隻在要比較的字符串的長度比較大時有效。若是字符串長度比較小,可能不如strcmp.
4.5 對比各類輸入輸出函數
行輸入函數的比較
【C語言】-->語法 fgets函數原理初探 - 省 - 博客頻道 - CSDN.NET
http://blog.csdn.net/chenglibin1988/article/details/8738070fgets函數在運行過程當中使用到了兩個緩衝區,一個是stdio緩衝區,一個是用於存放用戶輸入的緩衝區。系統調用read把數據讀入緩衝區stdiok ,fgets函數從stdio緩衝區中讀取一行,或規定數量的內容到本身函數參數中規定的緩衝區。
緩衝區stdio的標準容量是4kb,可是可使用setvbuf來擴容。
fgets函數原型爲
char *fgets(char *s, int n, FILE *stream);從stream(一般是stdin)所指的文件讀入字符到s所指的內存空間中,直到讀到換行符、文件尾或n-1個字符爲止,最後會加上NULL 做爲字符串結束,即s[n-1] = NULL;若是在未讀到n - 1個字符時,讀到了換行符或者 文件結束標誌(EOF),那麼 就將換行符或者文件結束標誌(EOF)都讀到s中,此時,再在換行符或是文件結束標誌(EOF)後面添加 NULL。 由於這個函數會將換行讀入,因此通常不使用。仍是用gets_s函數。
對於須要進行海量數據的輸入輸出的程序,須要對輸入輸出環節進行優化。所以通常,不要使用getline函數來讀取數據,而是在自定義大小的輸入輸出函數中定義4MB的輸入緩衝區,而後將數據直接讀入緩衝區,須要時再取出一行的數據就能夠了。
另外,本來咱們在用字段分解輸入行的過程當中使用的是strtok函數,若是能將strspn函數和strcspn函數結合起來使用,效率將會獲得提高。
C語言中strspn()函數和strcspn()函數的對比使用_C 語言_腳本之家
http://www.jb51.net/article/71441.htm性能優化上須要有總體的成本意識,儘可能避免太依賴於運行環境或安裝等固定成本,讓其餘人看到代碼後也能嘗試運行一下。
公共子表達式的消除(CSE: common sub-expression elimination)是編譯器的優化方法之一,若是值相同的表達式在程序中出現屢次,則只須要計算一次的一種運算方法。
》》若是一個函數不須要返回值,必定不要定義相應的返回值。
統計帶小數部分的數
因爲浮點數的計算相比整數類型計算要慢 ,並且浮點數與字符串之間的轉換也很耗時,因此在須要大量進行浮點數計算時,能夠將其轉化爲整數運算。
方案一:對全部數據規定一個最多小數位N,全部輸入的數據在系統內部都保存成實際數據*10^N,這樣能夠將小數運算轉化爲整數運算。
方案二:若是對浮點數須要很高的精度,64位整數中能處理的十進制數最多19位,若超過這個位數,能夠將小數和整數部分分開存放在兩個64位整數中。例如:
23.333 在整數部分,存入23;小數部分存入333,固然也能夠對小數部分進行擴大後存儲。
60.1 整數部分60,小數部分100。
注意因爲小數部分和整數部分進行了分開存放,因此在進行加法減法運算時,相應的進位和借位須要本身處理。因此雖然64位整數在十進制中能夠有19位數,但在程序中的小數部分只能存放18位,最高位被看成進位和借位標誌。
整數轉換成字符串
sprintf函數能夠將整數輸出到字符串中。
斷定字符的字節數
處理UTF-8字符串的程序必須先斷定輸入字符的字節數。UTF-8的字節數根據UNICODE的值定義爲1-6個字節不等。但在2006年的iso中規定,不能對U+200000以上的字符位置進行分配,因此實際上UTF-8的字節數最大隻能到4字節。
對於漢字而言,少數漢字佔用3個字節,大多數漢字佔用4個字節。
半角/全角字符和UNICODE
所謂半角字符和全角字符其實並無標準定義,它是PC在性能低下時,限制字符表示爲等寬字體(fixed width font)的術語。
對於一些特定的問題可使用表格來減小計算量,或用來減小條件分支。
在UTF-8中ascii碼的編碼與原來一致,使用U+0000~U+007F.