[英]Strange behavior of float in function definition. And declaration-definition mismatch, yet it works, how?
即使聲明中 function 的簽名與定義不匹配,以下代碼如何工作? function 聲明的參數列表為空,但定義只有一個參數。 為什么編譯器不報錯?
#include <stdio.h>
double f(); //function declaration
int main(void)
{
printf("%f\n", f(100.0));
}
double f(double param) //function definition
{
return 5 * param ;
}
它編譯並運行良好( ideone )。
但是,如果我將定義中的參數類型從double
更改為float
,則會出現以下錯誤( ideone ):
prog.c:7:錯誤:“f”的類型沖突
prog.c:8:注意:具有默認提升的參數類型與空參數名稱列表聲明不匹配
prog.c:2: 錯誤: 'f' 的先前聲明在這里
float
有什么問題? 為什么它會給出錯誤float
而不是double
?
這是聲明和定義對的列表,以及哪些對有效,哪些無效:
作品( ideone )
double f(); //declaration double f(double param); //definition
不起作用( ideone )
double f(); //declaration double f(float param); //definition
作品( ideone )
float f(); //declaration float f(double param); //definition
不起作用( ideone )
float f(); //declaration float f(float param); //definition
所以看起來,只要參數類型是float
,它就不起作用!
所以我基本上有兩個問題:
float
時它不起作用?我嘗試理解第 §6.5.2.2 (C99) 部分,但該語言非常神秘,以至於我無法清楚地理解。 我什至不知道我是否閱讀了正確的部分。 所以請用簡單的話來解釋這些行為。
您認為聲明與定義不匹配的假設是不正確的。 (在 C++ 中會出現這種情況,但在 C 中不會出現這種情況)。 在 C 語言中
double f();
聲明沒有完全聲明function,即沒有介紹原型。 它只宣布 function f
存在並且它的返回類型是double
的事實。 它完全沒有說明f
s arguments 的數量和類型。 arguments 絕對可以是任何東西。 從這個意義上說,您示例中的聲明確實與定義相匹配(即,它與定義不矛盾,這對於 C 編譯器來說已經足夠了)。
如果你真的想要聲明一個沒有 arguments 的 function,你必須在參數列表中指定一個明確的void
double f(void);
這確實與定義相矛盾。 你原來擁有的東西沒有。
當您調用已用空參數列表()
聲明的 function 時,您有責任提供正確類型的正確數量的 arguments。 如果您犯了錯誤,則行為是未定義的。 這是當您將實際參數類型更改為float
時編譯器會警告您的內容。
您對聲明和定義的“對”的分析並不完全正確。 這是被誤導的。 這與聲明和定義無關。 這實際上是關於定義和調用function 的方式。 在原始情況下,您使用double
參數調用它,並且使用double
參數聲明 function。 所以一切都是匹配的。 但是當你用一個double
參數調用它並用一個float
參數聲明它時,你會得到一個不匹配的結果。
另請注意,當 function 被聲明為沒有原型時, float
arguments 始終提升為double
arguments。 因此,無法將float
參數傳遞給使用()
參數列表聲明的 function。 如果您想要float
arguments,請始終使用原型(同樣適用於char
和short
arguments)。
C 允許 function 聲明為空。 從 C99 6.7.5.3/14 開始:
function 聲明符中的空列表不是該 function 定義的一部分,它指定不提供有關參數數量或類型的信息。
這與void
參數列表不同,后者明確指出 function 沒有 arguments。 從 6.7.5.3/10 開始:
void
類型的未命名參數作為列表中的唯一項的特殊情況指定 function 沒有參數。
另請注意,如果未聲明類型,則您的聲明不是原型。 從 6.2.1/2 開始:
function 原型是聲明其參數類型的 function 的聲明。
第二個問題確實和C99 6.5.2.2/6有關:
如果表示被調用的 function 的表達式具有不包含原型的類型,則對每個參數執行 integer 提升,並將具有
float
類型的 arguments 提升為double
精度。
因此,在您的情況下,每當調用 function 時, float
都會被提升為double
,並且在調用堆棧(或eax
或其他任何東西)中放置一個double
。 但是,當然,如果您的 function定義采用float
,它將從調用堆棧中讀取一個float
,這將導致二進制不兼容。 編譯器知道這一點,因此會出現錯誤消息。
在 C 中,聲明中的空參數列表意味着 function 可以與 0 個或多個 arguments 一起調用。
此類函數在使用浮點數調用時,會隱式將其視為double
。 (和整數參數為int
。)
所以當你調用 foo(100.0) 時,你是用一個 double 調用它。 如果您嘗試使用浮點數調用它,則參數將在調用時轉換為雙精度。
如果您將 function 定義為浮點數,這將不起作用,因為雙精度數和浮點數的傳遞方式不同。 因此,編譯器很有幫助地給你一個錯誤。
很高興你在 2011 年而不是 1985 年犯了這個錯誤,因為編譯器過去非常愚蠢,這是一個難以追蹤的噩夢般的錯誤。
底線:在現代 C 中聲明具有空參數列表的函數是非常糟糕的風格。 正確聲明 function,如果要被多個翻譯單元引用,則將聲明放入 header 文件中。
[編輯]
正如評論中詳細指出的那樣,如果您真的想聲明 function 為零 arguments,請聲明它為void
。 (或切換到 C++...)
在 C 中,一個空的 function 聲明就像在 C++ 中使用...
也就是說,它匹配任何數量和類型的 arguments。 使用float
而不是double
的問題是float
會自動提升為double
。 當調用f(...)
(借用 C++ 表示法)時,它不知道預期的類型,所以它被提升為 double。 稍后,當您重新聲明f
以采用float
參數時,這與 f 的隱式聲明為f
f(double)
沖突。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.