[英]Why does the standard let functions that don't return compile?
即使它的簽名說它應該,f()也不會返回。 為什么允許這個編譯? C標准是否有理由不要求編譯器使其失敗?
我知道它是未定義的行為和所有,但為什么它首先被允許? 有歷史原因嗎?
double f(){}
int main()
{
f();
return 0;
}
C標准是否有理由不要求編譯器使其失敗?
通過調用未定義的行為,C標准允許編譯器不那么復雜。 確實存在一些情況,例如if
語句,很難說函數是否返回值:
int f(int n)
{
if (n > 0) return 1;
}
f(5)
,編譯器很容易說該函數是正確的。 f(-5)
,也很容易檢測到未定義的返回值。 但是,如果參數來自用戶輸入,例如,編譯器應該如何知道函數是否返回值? 由於這可能是一個有效或錯誤的程序,C標准允許編譯器做他們想要的。 C旨在盡可能智能和簡單。
編譯器肯定會分析函數的所有代碼路徑,並拒絕該計划,如果它不能證明該函數總是返回一個有意義的值。 我認為標准沒有強制要求的原因是,在過去,編譯器的復雜性遠遠低於我們今天的工作。
當然使用這種函數的返回值是未定義的行為:
如果到達終止函數的},並且調用者使用函數調用的值,則行為是未定義的。
很容易判斷您的函數將在不返回值的情況下到達終點。 它不會返回,也不會調用任何可能阻止它到達終點的代碼(如abort()
)。
事實上,您的程序在C99中沒有未定義的行為,因為調用者不會使用缺少的返回值。 6.9.1 / 12:
如果到達終止函數的},並且調用者使用函數調用的值,則行為未定義。
所以你的代碼風格有問題,但定義明確。
C ++標准更改了[diff.stat]
該更改的規則和備注。 它說規則的C版本是支持在C不區分int
return和void
return的日子里寫回的代碼。 因此,您的代碼首先定義行為的原因是“遺留”。 也就是說,AFAIK C總是區分double
返回和int
返回,因此如果在正確的時間完成,它可能會使UB成為一個返回double
尾的函數。
暫且不管是否使用了返回值,請考慮一個tricker函數:
double f() {
if (g()) exit();
}
此函數也不包含return語句,但如果實際上g
總是返回true值或根本不返回,則不會到達函數的末尾。 因此,即使使用其返回值,也應該接受此函數,在一般的C標准原則上,您應該知道您正在做什么並且意味着您所說的。 如果g
在不同的TU中定義,那么您可能比編譯器更了解它。
即使它不是出於遺留原因,我也很確定標准根本無法添加文本以便定義需要檢測的非返回場景編譯器。 這取決於實現的質量 - 如果可以在編譯時確定您的函數不可能避免UB,那么編譯器可能會發出警告,盡管不需要診斷。 就此而言,當一般的C 實施者的原則定義行為時,它偶爾會發出警告,即某些事情是如此愚蠢,以至於任何用戶都無法合理地表達它們。
因為編譯器無法判斷函數是否在運行時返回。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.