簡體   English   中英

function 定義中浮動的奇怪行為。 聲明-定義不匹配,但它有效,如何?

[英]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,請始終使用原型(同樣適用於charshort 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM