2014-02-08 48 views
3

使問題清晰,我寫了一些測試代碼:調用函數

#include <stdio.h> 
#include <string.h> 

char *foo(int a) { 
    printf("%d\n", a); 
    static char string[2]; 
    string[0] = a > 0? '1' : '0'; 
    string[1] = '\0'; 
    return string; 
} 

int main(void) { 
    printf("%s\t%s\n", foo(1), foo(0)); 
    return 0; 
} 

運行代碼給出了這樣的輸出:

0 
1 
1  1 

我有這裏有兩個問題: 1.爲什麼在1之前打印0?在main的printf函數中,第二個foo會在第一個之前執行?這是一種確定的行爲還是偶然的。 2.爲什麼最終輸出1,1?預期的結果應該是1,0

+3

未指定函數參數的評估順序。 –

+0

@Enrico Granata - 他在問C而不是C++ – Joseph

+0

這將是學習如何使用調試器來遍歷代碼的好機會。逐步通過可能會讓你很清楚發生了什麼事情。 –

回答

2

論證評估的順序是依賴於實現的 - 你的編譯器恰好實現它

編輯方式:按你的第二個問題,您使用的是靜態緩衝區。這意味着它由兩個foo()調用共享 - 即兩個foo()調用都返回相同的指針。

根據您的評估訂單,首先寫入0,然後寫入1。在兩次foo()調用完成之前,打印緩衝區的時間是1,在這兩種情況下(緩衝區靜態==共享)。

如果你想解決這個問題,你可以讓調用者通過一個緩衝區,你的函數寫入用戶提供的內存,所以每次調用都是唯一的。

+0

這裏更重要的問題實際上是第二個問題 - 爲什麼是最終結果1,1? – Xufeng

+0

所以'print the string'move實際上是在printf的所有參數都被正確評估之後完成的? – Xufeng

+0

這是函數調用的方式,是的。 –

0

在你的例子中,是否首先調用foo(1)或foo(0)沒有在C中定義。在你的情況下調用foo(0),將foo的靜態字符串設置爲「0」並返回字符串的地址。然後調用foo(1),將字符串設置爲「1」。然後你打印字符串兩次。無論如何,它永遠都是一樣的。

+0

好的,我明白了。但是你是否也建議在printf中,在所有參數都被評估之後,兩個%s被替換? – Xufeng

+0

它們根本不被替換。該字符串的地址是'printf'函數的參數之一。 'printf'函數掃描該字符串並相應地解釋更多的參數。您傳入的兩個額外參數是foo中靜態字符串的地址,因此它們是相同的,並且會打印相同的字符串。 – ooga

+0

因此,編譯器首先評估參數,然後打印出整個字符串?因爲如果它在打印字符串時即時評估參數,這兩個%s應該有不同的值 – Xufeng

0

評估參數的順序是實現定義:

調用printf後:

printf("%s\t%s\n", foo(1), foo(0)); 

它要求foo()首先用0然後1。在每個呼叫中​​,String的地址被返回並存儲在一個變量中。由於Stringstatic,地址不變。通話結束後,來到printf以打印String內容,這是String發生的最後一次更改(在致電foo(1)後)。相同的地址意味着相同的值,意味着輸出是:

0 
1 
1  1 
+0

它對函數本身的打印輸出順序很重要 - 前兩行。 –

+0

@JoshCaswell是的,我錯過了它。 – rullof