2016-03-16 43 views
0

這個程序被稱爲localFunc.c文件中:本地(塊)函數decln與defn返回類型不匹配;診斷在C++?

#include <stdio.h> 

// int f(int); // Global forward declaration. 

int main() { 
    int f(int); // Local forward declaration. 
    printf("%d\n", f(1)); 
} 

double f(int i) { 
    return 1.0; 
} 

通過gcc localFunc.c編譯給出:

localFunc.c:10:8: error: conflicting types for ‘f’ 
double f(int i) { 
     ^
localFunc.c:6:7: note: previous declaration of ‘f’ was here 
    int f(int); // Local forward declaration. 

但通過g++ localFunc.c編譯,沒有任何錯誤和運行可執行文件的結果: 4195638

註釋掉本地前向聲明,並打開全局前向聲明:int f(int);,gcc和g ++都給出了與上面類似的錯誤,正如我所預料的那樣。

所以我的問題是,爲什麼g ++看不到本地聲明函數中的衝突類型(模糊聲明)?

[email protected]:~/UNIX/CS213$ gcc --version 
gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010 
+3

是不是像C和C++是不同的語言? –

+1

@Leushenko但你不能僅基於返回類型進行重載。另外,由於文件名,g ++可能會將代碼編譯爲C.無論哪種方式,它都不應該編譯。 – juanchopanza

+0

如果您想使用printf,請確保您傳遞正確的格式字符串。在這種情況下,我猜測使用了全局重載,所以應該使用'%lf'而不是'%d'。然而,我會推薦'std :: cout << f(1)<< std :: endl;' 請注意,gcc確實注意到這種不一致性,並告訴你它會遇到問題,很可能在1.0版本中會出現reinterpret_cast到int – JVApen

回答

5

我可以解釋C++的這種行爲。

從C++ 11規格,第3.5節[basic.link],第(7):

當與聯動的實體的塊範圍聲明不被發現提及某些其他聲明,那麼該實體是最內層封閉名稱空間的成員。但是,這樣的聲明不會在名稱空間範圍中引入成員名稱。

因此,int f(int)聲明具有全局鏈接,但不會將名稱引入全局名稱空間。這也許可以解釋爲什麼海灣合作委員會不會注意到衝突。

更重要的是,第(10)說:

的類型所有的調整之後(在此期間類型定義(7.1.3)由它們的定義被替換),參考給定的所有聲明中指定的類型變量或函數應該是相同的,除了數組對象的聲明可以指定由於存在或不存在主數組bound(8.3.4)而不同的數組類型。在類型標識上違反此規則不需要診斷。

您的程序違反了本段的「應該」部分,因此其行爲未定義。這意味着任何GCC都會做什麼 - 比如調用double foo(int)函數並將其返回值視爲int - 是規範允許的。而且,不需要診斷。

我不知道C說這個案子是什麼;特別是診斷是否是必需的。

+0

謝謝,這看起來似乎解釋了這裏發生的事情。所以應該小心地檢查一下,在一個塊中聲明的函數的函數類型是否與該函數的定義相匹配,因爲編譯器可能不會。 –

+0

@ user1666237:是的。此外,就我的經驗而言,這種對全球名稱的本地聲明非常不尋常......事實上,我從未在生產代碼中看到過這種聲明。通常的做法是將* all *非靜態聲明放入頭文件中,並在適當的時候放入'#include'。這樣,即使在翻譯單元中,編譯器也會告訴你這種不匹配。 – Nemo

+0

同意(評論> 15個字符) –

相關問題