Aquí está mi código. No importa lo que ingrese para el peso y la altura, siempre genera 0.0000000. No estoy seguro de qué tiene de malo.
#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; }Está utilizando una definición de función de estilo antiguo al no especificar los tipos de argumentos. Esto da como resultado que los argumentos tengan tipo int , lo que a su vez significa que está realizando una división de enteros.
Esto es realmente un comportamiento indefinido . Debido a que la función no especifica los tipos de los parámetros, la definición de la función tampoco especifica un prototipo para la función.
La sección 6.9.1p7 del estándar C con respecto a las definiciones de funciones establece:
El declarador en una definición de función especifica el nombre de la función que se define y los identificadores de sus parámetros. Si el declarador incluye una lista de tipos de parámetros, la lista también especifica los tipos de todos los parámetros; dicho declarador también sirve como prototipo de función para llamadas posteriores a la misma función en la misma unidad de traducción. Si el declarador incluye una lista de identificadores, 163) los tipos de los parámetros se declararán en una lista de declaración siguiente. En cualquier caso, el tipo de cada parámetro se ajusta como se describe en 6.7.6.3 para una lista de tipos de parámetros; el tipo resultante será un tipo de objeto completo.
Y la definición en cuestión tiene una lista de identificadores, no una lista de tipos de parámetros.
Esto significa que las únicas conversiones que ocurren en los argumentos son las promociones de argumento predeterminadas , que son solo promociones de enteros y conversión de float a double . El resultado es que los tipos de parámetros que se pasan (es decir, double ) no son compatibles con los tipos de parámetros esperados (es decir, int ), lo que desencadena un comportamiento indefinido.
Esto se detalla en la sección 6.5.2.2p6 con respecto a las llamadas a funciones:
Si la expresión que denota la función llamada tiene un tipo que no incluye un prototipo, las promociones de enteros se realizan en cada argumento y los argumentos que tienen tipo
floatse promueven adouble. Estas se denominan promociones de argumentos predeterminados. Si el número de argumentos no es igual al número de parámetros, el comportamiento no está definido. Si la función se define con un tipo que incluye un prototipo, y el prototipo termina con puntos suspensivos ( , ...) o los tipos de los argumentos después de la promoción no son compatibles con los tipos de los parámetros, el comportamiento no está definido. Si la función se define con un tipo que no incluye prototipo, y los tipos de los argumentos después de la promoción no son compatibles con los de los parámetros después de la promoción, el comportamiento es indefinido, excepto en los siguientes casos: ... [ no aplicable]
Debe establecer explícitamente los tipos de los parámetros:
double bmi(double w, double h){ double bmi = w/h; return bmi; }Hacer double bmi(w,h) a double bmi(double w, double h) . Sin una declaración explícita del tipo de argumento, el valor predeterminado es int .
warning: type of 'w' defaults to 'int' [-Wimplicit-int] 5 | double bmi(w,h){ | ^~~Entonces, con el tipo relevante:
double bmi (double w, double h) { return (w / h); } Active siempre la advertencia del compilador. Si tiene un sistema operativo Linux, use un alias. Para GCC en mi Ubuntu, uso algo como el siguiente para el código de prueba:
alias gcdev='gcc -Wall -Wextra -pedantic -g3 -O2 -fsanitize=address,undefined -std=c17 -march=native -I./include'Si lee las advertencias del compilador cuidadosamente dice
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] Entonces, si declara el tipo de datos de w y h como doubles , estará bien.
Esta es una especie de función de estilo antiguo y se puede activar mediante el uso -Wold-style-definition al compilar.
Ahora, dirá que está creando una variable double bmi en su función bmi , por lo que debería devolver un valor adecuado. Pero no es así porque cualquier operación entre dos int siempre devolverá un int . Use las banderas -std=c17 para mantenerse actualizado con los estándares C. Y eso es comportamiento indefinido de UB .
Contexto principal de cppreference.com sobre UB :
Comportamiento indefinido: no hay restricciones en el comportamiento del programa. Ejemplos de comportamiento indefinido son accesos a la memoria fuera de los límites de la matriz, desbordamiento de enteros con signo, desreferencia de puntero nulo, modificación del mismo escalar más de una vez en una expresión sin puntos de secuencia, acceso a un objeto a través de un puntero de un tipo diferente, etc. Compiladores no se requieren para diagnosticar un comportamiento indefinido (aunque se diagnostican muchas situaciones simples), y no se requiere que el programa compilado haga nada significativo.
Se requiere que los compiladores emitan mensajes de diagnóstico (ya sean errores o advertencias) para cualquier programa que viole cualquier regla de sintaxis C o restricción semántica, incluso si su comportamiento se especifica como indefinido o definido por la implementación o si el compilador proporciona una extensión de lenguaje que lo permite. para aceptar dicho programa. De lo contrario, no se requieren diagnósticos para comportamiento indefinido.
Los programas C correctos están libres de un comportamiento indefinido, los compiladores pueden producir resultados inesperados cuando un programa que realmente tiene UB se compila con la optimización habilitada:
También noté que su variable y nombre de función son los mismos, lo cual también es un problema. Entonces, use cualquier otro nombre como val o bmi_val .
No está comprobando el resultado de la función scanf() , comprueba si hay algún tipo de formato incorrecto.
Su función debe ser TRY IT ONLINE :
double bmi(double w, double h) { return w / h; } Indicadores GCC recomendados para advertencias:
-g -W -Wall -Wextra -Wuninitialized -Wstrict-aliasing -ggdb3 -std=c17 -Wextra -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wshadow