C 編譯優化的幾個例子

2021-05-24 11:28:40 字數 1972 閱讀 5892

程式設計師一般都喜歡談論程式設計技巧,尤其是能優化程式效率的技巧,c++程式設計師都不例外。但很多廣泛流傳的技巧都是基於乙個假設,就是編譯器非常愚蠢。但事實上剛好相反,現在的編譯器其實非常聰明。不信的話你看下面的例子。

test函式的作用是返回從1加到100的值,大家都知道結果是5050。使用gcc編譯器將其編譯成彙編:

gcc -o2 -s test.c

vi test.s

生成的彙編:

test:

pushl %ebp

movl  $5050, %eax

movl  %esp, %ebp

popl  %ebp

ret編譯器也已經知道答案5050,所以當你呼叫test函式時直接返回5050而不需計算。怎麼樣,編譯器還不笨吧?

下面看看幾個常見的c++語句的編譯優化。為簡單起見,以下討論都基於gcc優化編譯。

有些人說不要用i++而要用++i,因為i++要先儲存原來的值會比較慢(據說有些書是這麼說的)。但事實上作為一條語句使用時(而不是作為表示式嵌入到語句中),無論i++、++i、i+=1或i=i+1編譯後都只使用一條指令(inc或add),效果是一樣的。當然作為表示式嵌入到語句中時會不一樣,但這時候i++和++i一般都不能混用。

c++**:

彙編**:

movl  8(%ebp), %ebx

movl  12(%ebp), %ecx

movl  16(%ebp), %edx

movl  20(%ebp), %eax

addl  $1, (%ebx)

addl  $1, (%ecx)

addl  $1, (%edx)

addl  $1, (%eax)

函式區域性變數使用的棧空間是在進入函式時一次分配的,而不是在宣告時分配,因此在迴圈裡宣告變數並不會導致效能下降。

彙編**:

movl  $10, %ebx

subl  $272, %esp            #分配272位元組棧空間

leal  -264(%ebp), %esi       #取buf位址

.l2:

movl  %esi, (%esp)          #buf位址入棧

call  test2                  #呼叫test2

subl  $1, %ebx

jne .l2                     #迴圈未結束則跳到l2

a*2被編譯成a+a;無符號數a/2被編譯成a>>1;有符號數a/2沒看懂,但不是除運算。

memset函式常用來初始化大段記憶體,但對小資料來說memset能否保持足夠高效呢?

看這段程式:

編譯成彙編:

movl  $0, -24(%ebp)         #設定s1

movl  $0, -20(%ebp)

movl  $0, -16(%ebp)

movl  $0, -12(%ebp)

call  test2                  #呼叫test2

leal  -8216(%ebp), %edx      #設定s2

xorl  %eax, %eax

movl  %edx, %edi

movl  $2048, %ecx

rep stosl

movl  %edx, (%esp)      #呼叫test2

call  test2

movl  %ebx, (%esp)      #設定s3

movl  $8193, 8(%esp)

movl  $0, 4(%esp)

call  memset

movl  %ebx, (%esp)      #呼叫test2

call  test2

當資料長度比較小時(如s1是16位元組),memset被編譯成連續的賦值語句;當資料長度不大於8kb時(如s2),memset用串操作指令來實現;當資料長度大於8kb時(如s3),memset被編譯成函式呼叫。

EnumSet的幾個例子

enumset 是乙個與列舉型別一起使用的專用 set 實現。列舉set中所有元素都必須來自單個列舉型別 即必須是同型別,且該型別是enum的子類 列舉型別在建立 set 時顯式或隱式地指定。列舉 set 在內部表示為位向量。此表示形式非常緊湊且高效。此類的空間和時間效能應該很好,足以用作傳統上基於...

儲存過程幾個例子

create or replace procedure peace if is cursor var c is select from grade begin for temp in var c loop if temp.course name os then dbms output.put lin...

java註解的幾個例子

註解的生命階段 1.原始檔 source 2.class檔案 class 3.記憶體中 runtime retentionpolicy 是乙個列舉 一共就這三個值,用來表示註解的生命階段 override retentionpolicy.source suppresswarnings retenti...