2017-02-04 74 views
6

來自K & R Book on C,我收集了如果函數原型聲明省略參數(如在int foo();中),則關閉類型和參數檢查並且不會假定關於參數與舊版本的C兼容,因此它不會破壞舊版代碼。函數原型 - 關閉參數檢查

但下面的代碼拋出一個編譯錯誤的原型不匹配:

#include <stdio.h> 
void test(); 
int main(void) { 
    test(34.5f); 
} 

void test(float a) { 
    printf("%f\n", a); 
} 

錯誤:

C:\***.c:7:6: error: conflicting types for 'test' 
void test(float a) { 
    ^

任何解釋嗎?

+5

gcc增加:'注意:具有默認提升的參數類型不能匹配空參數名稱列表聲明',所以'void test(double a)'工作,但'void test(float a)'doesn 「T。因此,似乎「關閉了類型和參數檢查並且沒有任何關於爭論的事情」是過於簡單化了。您應該參考C規範以查看規則的實際內容。 – ikegami

+0

請參閱http://stackoverflow.com/questions/1630631/alternative-kr-c-syntax-for-function-declaration-versus-prototypes某些人可能會認爲這個問題是該問題的重複,並關閉。 –

+1

編譯器期望定義'void test(double a){}',因爲'test(34.5f);'調用涉及_default參數promotions_,如果給定的聲明不作爲原型,就是這種情況。其中一種促銷是「float ---> double」。 –

回答

-1

你告訴gcc編譯c11代碼,而不是爲K & R.

我看着-std=選項,但沒有人站出來爲有用。也許完全省略語言標準參數會有所幫助。或者將其指定爲c89

在c11中,總是需要完整形狀的原型。所以第一次使用的功能是參數= (void)。在pre-C++中,這確實意味着「可能有或沒有參數通過」。

+0

,它仍然是一個錯誤「在c11中,總是需要完整形狀的原型。」Citation? – Ryan

+0

nope,用c89試過。沒有使用這個編譯。 – BalaK

+0

@Ryan:這不是c11的主要增強之一嗎?或者,也許我正在考慮C++ 11? – wallyk

5

當函數聲明不止一次時,所有聲明必須有兼容類型(C11 6.2.7/2)。在你的代碼f被聲明兩次 - 定義也算作一個聲明。

「兼容功能型」 的定義是在C11 6.7.6.3/15:

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

因此void test()void test(float)是不相容的。換句話說,看到void test();後,任何原型只能使用默認參數促銷不變的類型。在這些促銷活動下,float更改爲double

我相信自從第一個C標準以來就一直如此。

1

使用double類型的參數定義函數。

void test(double a) { 
    //... 
} 

的問題是在這個呼叫

test(34.5f); 

有使用默認參數推廣是將參數轉換成double類型。

+1

即使沒有函數調用,代碼仍然是違反約束的 –

0

因此,最後從這裏給出的所有答案以及一點點閱讀中,我學到了這些(我將它作爲答案發布,以便將來任何人都可能會遇到這個問題) :

  • 當我打電話test(23.4f) - 參數自動「強制」爲雙和,因爲沒有指定原型將被稱爲test(double)(爲自變量,至少)
  • 由於任何呼叫我讓使用任何參數將被轉換爲'默認促銷',我不能將函數聲明爲test(float),因爲它永遠不會被使用/調用編輯。因此,test(double)作品和test(float)不。

糾正我,如果我錯了,我會編輯我的答案。

1

根據錯誤消息,具有默認升級的參數類型不能匹配空參數名稱列表聲明。所以問題是float將被提升爲int,這會導致與函數定義的參數float不匹配。

聲明:

void test(); 

它告訴了存在功能test這是任何參數,而不是返回一個值的編譯器。

定義:

void test(float a) 

這是告訴編譯器什麼test()實際上也提供了申報爲好。