彙編角度來分析C 優化

2021-06-17 23:47:03 字數 3107 閱讀 3126

以前學過一陣子彙編,後來又忘記了不少,最近翻起來,又發現在c++層其實有很多可以程式設計習慣,可以根據彙編原理進行優化。

//****************************************=

1:多使用float.

為了讓編譯器產生更好的3dnow!或sse指令**,我們可以必須確定浮點型變數和表示式是float型的,為避免float自動轉換為double,我們宣告時需要強調,並在後面加以f字尾。

//****************************************=

2:適時使用無符號整形

1)int轉換float/double型別時,建議使用有符號整形,因為x86構架中,提供了從int轉換為float/double型別的指令,而沒有提供unsigned int轉換為浮點型的指令,我們看下編譯器反彙編後的彙編**。

double x;          mov [temp + 4], 0

unsigned int x;    mov eax, i

x = i;             mov [temp], eax

flid qword ptr [temp]

fstp qword ptr [x]

這段**不僅指令數多,而且因為指令配對失敗造成的flid指令會被延遲執行,**執行較慢。

而使用無符號整形的話,會快的多,反彙編如下

double x;         flid qword ptr [i]

int i;            flid qword ptr [x]

x = i;

指令配對,**執行較快

2)對整形求商求余時,使用無符號整形會比較快,我們也以彙編**檢視分析

int i;               mov eax, i

i = i / 4;           cdq

and edx, 3

and edx, edx

sar eax, 2

mov i, eax

而當我們使用無符號整形時

unsigned int i;              shr i, 2

i = i / 4;

3)同樣,在迴圈計數,陣列下標時,盡可能的使用無符號整形,會提高**執行速度。

//****************************************=

3:多使用for,少使用while

我們依舊是看反彙編**。

while( 1 );                      mov eax, 1

test eax, eax

je temp+23h

jmp temp+18h

而for的則是

for( ; ; );                      jmp temp=23h

//****************************************=

4:多使用陣列,少使用指標

我這條建議恐怕要受到廣大c++程式設計師的責罵與非議,而實際上編譯器是很難對指標進行優化的,因為預設的編譯器會假設指標可以訪問任何的記憶體位址。而我們使用操作符來訪問陣列的話,會讓編譯器減少產生不安全**的問題

//****************************************=

5:迴圈的優化

1)人工拆分小迴圈

為了充分的利用cpu的指令快取,我們可以把一些很小的迴圈手工拆開,雖然這樣寫出的**會顯得有些冗餘「低水平」,而這樣做的確可以提高效能。例如

// 3d轉化:把向量v和4x4矩陣m相乘

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

}我們可以將其拆分為

// 3d轉化:把向量v和4x4矩陣m相乘

r[0] = m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3];

r[1] = m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3];

r[2] = m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3];

r[3] = m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3];

2)小迴圈寫外,大迴圈寫裡,這樣可以避免斷掉cpu的連續迴圈指令。例如

for( unsigned int i=0; i<=10; ++i )  }

就比下面的好

for( unsigned int j=0; j<=10000; ++j )  }

同樣的道理,迴圈與判斷巢狀時,我們也可以將判斷放外,迴圈放內比較好,避免判斷打斷迴圈指令。

//****************************************=

6:避免使用無必要的讀寫依賴

當資料儲存到記憶體時存在讀寫依賴,儘管amd athlon等cpu有加速讀寫依賴延遲的硬體,允許將儲存的資料在寫入前讀取出來,但是,我們手工將讀寫儲存去除的話,**效能能有很大的提公升。

我們的做法通常是犧牲一定的空間在暫存器中建立乙個臨時變數。

//****************************************=

7:優化switch

switch可能使用多種演算法進行優化,其中最普通的是跳轉表和比較鏈。我推薦大家將最有可能的case放在第一位,此時比較鏈會得到一定效能的提高,另外,case盡量使用比較小的連續整數,因為此時編譯器會將switch轉化為跳轉表。

//****************************************=

8:盡量多的使用常量const

因為c++標準規定,若乙個const物件的位址不被獲取,編譯器可以不對它分配儲存空間。

//****************************************=

9:多使用內聯函式和靜態函式

當然,內聯函式不是越多越好,它是以**膨脹以代價的加速,根據需要吧。而static強制使用內部連線的函式可以進行**的優化,不然編譯器預設的會把函式定義為外部連線。

//****************************************=

困了,今天就先分析到這裡。

在彙編的角度來理解C語言3級指標

c語言中指標使用頻率是很高的,我們知道指標乙個特殊的變數,它的值是指向一塊記憶體位址 我寫了乙個簡單的c void test1 編譯,然後ollydbg載入 我們一句句來 mov dword ptr ss ebp 0xc 0x0 將值0 放入棧空間位址 ss ebp 0xc 實體地址為 00d3fb...

介面和抽象類 設計角度來分析

1.抽象類和介面的語法特性 抽象類不允許被例項化,只能被繼承.它可以包含屬性和方法.方法既可以包含 的實現,也可以不包含 的實現.不包含 的實現叫做抽象方法.介面不能包含屬性,只能宣告方法,方法不能包含 實現.類實現介面的時候,必須實現介面中宣告的所有方法.2.抽象類和介面存在的意義 抽象類是對 成...

C 從彙編角度詳解函式呼叫棧

先來看一段 int sum int a,int b intmain 有兩個問題 main函式呼叫sun,sum執行完之後怎麼知道回到哪個函式?sum函式執行完,回到main之後,怎麼知道從哪一行指令繼續執行?我們現在從彙編角度看這段 首先main還是會先開闢棧幀 mov dword ptr ebp ...