2014-12-05 27 views
5

我現在想學習C/C++的基礎知識。我正在閱讀Lynda.com上的課程新手在這裏:PC和MAC上的不同結果。爲什麼?

我的問題涉及第4章「來自課程C/C++基礎培訓的宏警告」中的一系列代碼。我已經遵循了所有的安裝程序,以便在PC上的Mac和Eclipse上正確地安裝Xcode和Eclipse。當我在MAC和PC上運行此代碼時,我得到了不同的結果。試圖瞭解爲什麼會發生這種情況,以及我可以如何才能在兩者上獲得相同的結果。

下面是代碼:

// working.c by Bill Weinman <http://bw.org/> 

#include <stdio.h> 
#define MAX(a, b) ((a) > (b) ? (a) : (b)) 

int increment() { 
    static int i = 42; 
    i += 5; 
    printf("increment returns %d\n", i); 
    return i; 
} 

int main(int argc, char ** argv) { 
    int x = 50; 
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment())); 
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment())); 
    return 0; 
} 

在PC上我得到這樣的結果:

increment returns 47 
increment returns 52 
max of 50 and 52 is 50 
increment returns 57 
increment returns 62 
increment returns 67 
max of 50 and 67 is 62 

在Mac上(的Xcode和Eclipse兩者)我得到這樣的結果:

increment returns 47 
increment returns 52 
increment returns 57 
max of 50 and 47 is 57 
increment returns 62 
increment returns 67 
increment returns 72 
max of 50 and 62 is 72 

爲什麼會發生這種情況,我該怎麼做以確保結果相同?

+1

順便說一句:IDE並不代表任何東西,確切的編譯器和你給它的選項,在幾乎每一種情況下都會決定順序。雖然它在理論上可能會隨着程序的每次執行而改變。 – Deduplicator 2014-12-05 17:46:52

+1

@AdrianoRepetti幾乎肯定是一個dup,但因爲我對這個問題有一個答案,我不想重複關閉它。 – 2014-12-05 17:57:30

回答

8

你在這裏有未指定的結果。

printf()中的評估順序未定義。 一旦你在同一個printf中有多個increment()調用,那麼你永遠不會知道哪個是先執行的,以及如何評估它們。

2

這裏有兩個問題。

您正在依賴編譯器選擇用於評估printf()的參數。評估的語句首先修改後面的語句的值。將increment()調用移出參數列表。將increment()的結果存儲在變量中,並將這些變量傳遞給printf()。

此外,MAX的宏擴展可以使任一參數被評估一次或兩次。因此,即使在同一個操作系統和編譯器中,您也可能會遇到不好的結果。要解決這個問題,請按照我建議的方式來存儲increment()結果。將這些變量傳遞給MAX()。

6

未定義全表達式中所有元素得到評估的順序。所需要的是,每個子表達式在評估之前都有其操作數完全評估。在函數調用的情況下,參數可以按任意順序求值,實際上一個參數可能只有部分在另一個參數完全評估的時刻被求值。

首先,讓我們展開宏:

printf("max of %d and %d is %d\n", x, 
            increment(), 
            ((x) > (increment()) ? (x) : (increment())); 

(抱歉,這裏是另外一個問題:如果increment()大於x然後它被再次呼籲充分利用MAX宏函數代替參數是隻評估一次!)

以下所有序列都是可能的。我在這裏省略了x的評估,因爲它不會改變。

  • 第二個參數increment()被評估,隨後x > increment(),最後接着被選擇取其?:操作數。(這可能是您期望的順序。)
  • x > increment()將被評估,然後選擇無論哪個?:操作數被選中,最後跟第二個參數increment()
  • x > increment()被評估,接着是第二個參數increment(),最後跟着選擇任何一個?:操作數。

這些可能會產生不同的結果,它們都是您的代碼的正確解釋。

當您在單個完整表達式中調用多個函數時,應該確保這些函數沒有任何副作用,或者每個函數的副作用不會改變任何一個函數的行爲其他功能。否則,在不同的編譯器(或同一編譯器的不同版本)上編譯可能會改變結果。

作爲一個附加例子,即使簡單表達式increment() > increment()也有未指定的結果,因爲操作數的求值順序沒有定義;如果左邊的操作數首先被求值,那麼結果將是假的,否則它將是真的。

在更復雜的例子((a + b) * (c + d))編譯器可以評估abcd以任何順序,它高興。所需要的所有是ab必須進行評估之前a + b就可以了,cd必須進行評估之前c + d就可以了,a + bc + d必須在最終操作員*可前後進行評估。

相關問題