img attribute c gcc math.h constantfolding

c - img - title html attribute



log(10.0) puede compilar pero log(0.0) no puede? (2)

Para el siguiente código fuente C :

#include <math.h> int main(void) { double x; x = log(0.0); return 0; }

Cuando compilo con gcc -lm , obtuve:

/tmp/ccxxANVH.o: In function `main'': a.c:(.text+0xd): undefined reference to `log'' collect2: error: ld returned 1 exit status

Pero, si reemplazo log(0.0) con log(10.0) , entonces puede compilarse con éxito.

No entiendo muy bien esto, ya que no importa si tienen sentido matemático o no, deberían compilarse: no hay ningún error de sintaxis. ¿Alguien podría explicar esto?

Por si acaso, mi salida gcc -v :

Configured with: ../src/configure -v --with-pkgversion=''Ubuntu 4.8.2-19ubuntu1'' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

Tenga en cuenta que esta pregunta se trata de plegamiento constante, pero la pregunta duplicada sugerida se trata de una biblioteca de enlaces que falta.


La compilación está bien, es solo el interruptor del enlazador -lm que falta.

La segunda versión probablemente compila y enlaza porque gcc reemplaza log(10.0) con una constante, por lo que no se necesita llamar a la biblioteca matemática. En el segundo caso, el resultado es matemáticamente indefinido, y la evaluación da como resultado un error de dominio. En ese caso, la expresión no puede ser reemplazada por una constante, ya que el manejo de los errores de dominio puede ser diferente en el tiempo de ejecución.

Cita del C-estándar ( draft ):

En un error de dominio, la función devuelve un valor definido por la implementación; si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor EDOM; si la expresión entera math_errhandling & MATH_ERREXCEPT es distinta de cero, se genera la excepción de punto flotante '''' no válida ''''.

Por lo tanto, la evaluación de log(0.0) da como resultado la devolución del valor HUGE_VAL (no NAN como he afirmado anteriormente) o una excepción de coma flotante.

EDITAR: Corregí mi respuesta en función de los comentarios recibidos y agregué un enlace a la descripción en el estándar C.


gcc puede usar funciones integradas en muchos casos, su documentación dice:

Muchas de estas funciones solo están optimizadas en ciertos casos; si no están optimizados en un caso particular, se emite una llamada a la función de la biblioteca.

por lo tanto, gcc no necesitará vincularse con la biblioteca matemática cuando use la función incorporada, pero como log(0) no está definido , probablemente gcc a gcc a evaluarlo en tiempo de ejecución ya que tiene un efecto secundario.

Si miramos el borrador de la sección estándar del C99 7.12.1 Tratamiento de las condiciones de error en el párrafo 4 , dice (el énfasis es mío ):

Un resultado flotante se desborda si la magnitud del resultado matemático es finita pero tan grande que el resultado matemático no se puede representar sin un error de redondeo extraordinario en un objeto del tipo especificado. Si un resultado flotante se desborda y el redondeo predeterminado está activo, o si el resultado matemático es un infinito exacto de argumentos finitos (por ejemplo, log (0.0)), la función devuelve el valor de la macro HUGE_VAL, HUGE_VALF o HUGE_VALL de acuerdo con el tipo de devolución , con el mismo signo que el valor correcto de la función; si la expresión entera math_errhandling & MATH_ERRNO es distinta de cero, la expresión entera errno adquiere el valor ERANGE; si la expresión entera math_errhandling & MATH_ERREXCEPT no es cero, la excepción de punto flotante '''' divide por cero '''' se produce si el resultado matemático es un infinito exacto y la excepción de punto flotante '''' overflow '''' se plantea de otra manera.

Podemos ver a partir de un ejemplo en vivo usando el indicador -S para generar el ensamblaje y el grep log para filtrar las llamadas al log .

En el caso de log(0.0) se genera la siguiente instrucción ( ver en vivo ):

call log

pero en el caso de log(10.0) no se genera instrucción de call log , ( ver en vivo ).

Por lo general, podemos evitar que gcc use la función incorporada mediante el uso del indicador -fno-builtin, que probablemente sea una forma más rápida de probar si se está utilizando una función incorporada.

Tenga en cuenta que -lm necesita buscar el archivo fuente , por ejemplo ( tomado de la respuesta vinculada ) si main.c requirió la biblioteca matemática, entonces usted usaría:

gcc main.c -lm