C語言一題

一、問題來源
  一日,老婆下班回來,說要測試一下我的C語言還記得多少,頓時驚起一身冷汗,哈哈,這個東西已有很久沒有用了。細節怕是……。接下問題開始下文。               
二、問題描述
  以下兩種程序寫法有何不同:
  1.
#include <stdio.h>

#define sq(y) ((y)*(y))

void main (void)
{
    int i =1 ;
    while(i<=5)
        printf("%d/n",sq(i++));
}           
    2.
#include <stdio.h>

int sq(int y)
{
    return y*y;
}
void main (void)
{
    int i =1 ;
    while(i<=5)
        printf("%d/n",sq(i++));
}

三、問題解釋
    乍一看感覺沒什麼,但一思考,想法還是很多:
  • 這兩段代碼一個採用了函數,另一個使用了宏定義。函數的參數類型是限制死的,而宏就可以隨便了。
  • 因爲宏定義在編譯時是要進行替換的,所以還有一個差別就在這個i++上了,宏一個每次循環i加兩次,而函數只加一次了,所以兩個的執行結果肯定不同。
     解釋完了,老婆又問那兩個的值分別是什麼呢。頓時又有了新的想法。函數的執行結果很顯而易見,就不說了。而這個宏定義,可是大有文章了。爲什麼呢,差別就在這個地方((i++)*(i++))這個東西的執行結果是什麼呢,就是不同的編譯器編譯的執行結果不同。在VC中是先乘在加兩次(請看對應的彙編代碼)。所以結果是:
1,9,25

彙編代碼如下:
    mov    eax, DWORD PTR _i$[ebp]
    imul    eax, DWORD PTR _i$[ebp]
    mov    DWORD PTR -8+[ebp], eax
    mov    ecx, DWORD PTR -8+[ebp]
    push    ecx
    push    OFFSET FLAT:??_C@_03HMFC@?$CFd?6?$AA@    ; `string'
    mov    edx, DWORD PTR _i$[ebp]
    add    edx, 1
    mov    DWORD PTR _i$[ebp], edx
    mov    eax, DWORD PTR _i$[ebp]
    add    eax, 1
    mov    DWORD PTR _i$[ebp], eax
    call    _printf

而在使用sco unix 的編譯環境編譯後的執行結果則大不相同(這個是符合一般的想法的)。所以這種寫法是不可取的,因爲移植性沒有。所以儘量不能這樣寫((i++)*(i++))。  
使用宏這種方式有什麼優勢呢,就是減少了函數執行時的性能消耗,這個對於嵌入式系統來說可是很關鍵的。個人認爲這點可能比出題人設計的無聊的無確定結果的題目更應該被人理解和記住。

   歡迎不吝賜教。
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章