這是我的代碼。無論我輸入什么體重和身高,它總是輸出 0.0000000。我不確定它有什么問題。
#include <stdio.h>
#include <math.h>
double bmi(w,h){
double bmi = w/h;
return bmi;
}
int main() {
double height;
double weight;
printf("Enter your height in meters: ");
scanf("%lf", &height);
height = pow(height, 2);
printf("Enter your weight in kilograms: ");
scanf("%lf", &weight);
printf("Your BMI is %f\n", bmi(weight, height));
return 0;
}
uj5u.com熱心網友回復:
您通過不指定引數的型別來使用舊式函式定義。這導致引數具有 type int,這反過來意味著您正在執行整數除法。
這實際上是未定義的行為。因為函式沒有指定引數的型別,所以函式定義也沒有指定函式的原型。
C 標準關于函式定義的第 6.9.1p7 節指出:
函式定義中的宣告符指定被定義函式的名稱及其引數的識別符號。如果宣告符包含引數型別串列,該串列還指定了所有引數的型別;這樣的宣告器還可以用作函式原型,以便以后呼叫同一翻譯單元中的同一函式。如果宣告符包括一個識別符號串列,163) 引數的型別應在下面的宣告串列中宣告。在任何一種情況下,每個引數的型別都按照 6.7.6.3 中對引數型別串列的描述進行調整;結果型別應為完整的物件型別。
并且有問題的定義有一個識別符號串列,而不是引數型別串列。
這意味著在引數上發生的唯一轉換是默認引數提升,它只是整數提升和 to 的float轉換double。結果是傳遞的引數型別(即)double與預期的引數型別(即)不兼容int,從而觸發未定義的行為。
這在關于函式呼叫的第 6.5.2.2p6 節中有詳細說明:
如果表示被呼叫函式的運算式的型別不包含原型,則對每個引數執行整數提升,并將具有型別的引數
float提升為double. 這些稱為默認引數提升。如果引數的數量不等于引數的數量,則行為未定義。如果函式使用包含原型的型別定義,并且原型以省略號 ( , ...) 結尾,或者提升后的引數型別與引數型別不兼容,則行為未定義。如果函式是用不包含原型的型別定義的,并且提升后的引數型別與提升后的引數型別不兼容,則行為未定義,下列情況除外: ... [不適用]
您需要顯式設定引數的型別:
double bmi(double w, double h){
double bmi = w/h;
return bmi;
}
uj5u.com熱心網友回復:
使。double bmi(w,h)_ double bmi(double w, double h)如果沒有顯式宣告引數型別,它默認為int.
warning: type of ‘w’ defaults to ‘int’ [-Wimplicit-int]
5 | double bmi(w,h){
| ^~~
因此,使用相關型別:
double bmi (double w, double h) {
return (w / h);
}
始終打開編譯器的警告。如果您使用的是 linux 作業系統,請使用別名。在GCC我的 Ubuntu 上,我使用類似下面的代碼來測驗代碼:
alias gcdev='gcc -Wall -Wextra -pedantic -g3 -O2 -fsanitize=address,undefined -std=c17 -march=native -I./include'
uj5u.com熱心網友回復:
如果仔細閱讀編譯器警告說
warning: type of 'w' defaults to 'int' [-Wimplicit-int]
1 | double bmi(w,h){
| ^~~
<source>:1:8: warning: type of 'h' defaults to 'int' [-Wimplicit-int]
因此,如果您將wand的資料型別宣告h為doubles,那么就可以了。
這是一種老式的功能,可以-Wold-style-definition在編譯時使用標志打開。
現在,您會說您正在函式中創建一個double變數,因此它應該回傳一個正確的值。但這不是因為兩個s 之間的任何操作都將始終回傳一個。使用標志讓自己與 C 標準保持同步。那就是未定義的行為。bmibmiintint-std=c17UB
cppreference.com關于UB的主要背景:
未定義的行為 - 對程式的行為沒有限制。未定義行為的示例包括陣列邊界之外的記憶體訪問、有符號整數溢位、空指標取消參考、在沒有序列點的運算式中多次修改同一標量、通過不同型別的指標訪問物件等。不需要診斷未定義的行為(盡管診斷了許多簡單的情況),并且編譯的程式不需要做任何有意義的事情。
編譯器必須為任何違反任何 C 語法規則或語意約束的程式發出診斷訊息(錯誤或警告),即使其行為被指定為未定義或實作定義,或者如果編譯器提供允許它的語言擴展接受這樣的計劃。否則不需要對未定義行為進行診斷。
正確的 C 程式沒有未定義的行為,當實際具有 UB 的程式在啟用優化的情況下編譯時,編譯器可能會產生意想不到的結果:
我還注意到您的變數和函式名稱相同,這也是一個問題。因此,請使用任何其他名稱,例如valor bmi_val。
您不是在檢查scanf()函式的結果,而是檢查任何型別的錯誤格式。
你的功能應該是TRY IT ONLINE:
double bmi(double w, double h)
{
return w / h;
}
Recommeded GCC flags for warnings:
-g -W -Wall -Wextra -Wuninitialized -Wstrict-aliasing -ggdb3 -std=c17 -Wextra -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wshadow
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/448225.html
標籤:C
