
xuhdev
Para el siguiente C código fuente:
#include <math.h>
int main(void)
{
double x;
x = log(0.0);
return 0;
}
Cuando compilo con gcc -lm
Tengo:
/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 compilar con éxito.
No entiendo muy bien esto, ya que no importa si tienen sentido matemático o no, deben compilarse, no hay error de sintaxis. ¿Alguien podría explicar esto?
Por si acaso, mi gcc -v
producción:
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 es sobre el plegado constante, pero la pregunta duplicada sugerida es sobre una biblioteca de enlaces faltante.

Shafik Yaghmour
gcc
puedo usar funciones integradas en muchos casos, su documentación dice:
Muchas de estas funciones solo se optimizan en determinados casos; si no están optimizados en un caso particular, se emite una llamada a la función de biblioteca.
asi que, por lo tanto gcc
no necesitará vincularse con la biblioteca matemática cuando use la función incorporada, pero dado que log(0)
es no definida probablemente obligagcc
para evaluarlo en tiempo de ejecución ya que tiene un efecto secundario.
Si nos fijamos en el borrador del estándar C99 sección 7.12.1
Tratamiento de las condiciones de error en el párrafo 4 dice (énfasis 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á en vigor, o si el resultado matemático es un infinito exacto a partir de argumentos finitos (por ejemplo, log(0.0)), la función devuelve el valor de la macro HUGE_VAL, HUGE_VALF o HUGE_VALL según el tipo de devolucióncon 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 es distinta de cero, se genera la excepción de coma flotante “dividir por cero” si el resultado matemático es un infinito exacto y, de lo contrario, se genera la excepción de coma flotante “desbordamiento”.
Podemos ver en un ejemplo en vivo usando -S
bandera para generar ensamblado y grep log
para filtrar las llamadas a log
.
En el caso de log(0.0)
se genera la siguiente instrucción (verlo en vivo):
call log
pero en el caso de log(10.0)
no call log
se genera la instrucción, (verlo en vivo).
Por lo general, podemos prevenir gcc
de usar la función incorporada usando el -bandera incorporada de fno que es probablemente una forma más rápida de probar si se está utilizando una función integrada.
Tenga en cuenta que -lm
necesita ir después del archivo fuente, por ejemplo (tomado de la respuesta vinculada) si main.c
requiere la biblioteca de matemáticas, entonces usaría:
gcc main.c -lm

axel
La compilación está bien, es solo el interruptor del enlazador. -lm
eso falta
La segunda versión probablemente compila y vincula 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 no está definido matemáticamente y la evaluación da como resultado un error de dominio. En ese caso, la expresión no se puede reemplazar por una constante, ya que el manejo de los errores de dominio puede ser diferente en tiempo de ejecución.
Cita del estándar C (sequía):
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 coma flotante ”no válida”.
Así que evaluación de log(0.0)
cualquiera da como resultado la devolución del valor HUGE_VAL
(no NAN
como dije antes) 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.
Esto probablemente tiene que ver con la propagación constante y no especificar
-lm
.– Místico
18 de junio de 2014 a las 20:38
@Cornstalks De hecho, uno debería especificar
-lm
después del archivo fuente.– xuhdev
19 de junio de 2014 a las 4:00
No estoy de acuerdo con su premisa de que debe compilarse una expresión matemática indefinida. Dado que log(0) no está definido/singular, su presencia en un programa solo puede ser el resultado de un error de programación. No hubiera esperado que el compilador captara esto, pero considere el hecho de que hace un rasgoNo un defecto.
– Gdalya
25 de junio de 2014 a las 18:56
@gdalya debería devolver -Inf, no indefinido. Ver aquí
– xuhdev
25/06/2014 a las 19:35
@LưuVĩnhPhúc Son dos preguntas diferentes. Ver mi edición en la última línea.
– xuhdev
20 ago 2016 a las 17:30