¿Por qué tienes que vincular la biblioteca de matemáticas en C?

12 minutos de lectura

avatar de usuario
No

si incluyo <stdlib.h> o <stdio.h> en un programa C no tengo que vincularlos al compilar, pero sí tengo que vincularlos a <math.h>utilizando -lm con gcc, por ejemplo:

gcc test.c -o test -lm

¿Cuál es la razón para esto? ¿Por qué tengo que vincular explícitamente la biblioteca de matemáticas pero no las otras bibliotecas?

avatar de usuario
Nosredna

Recuerde que C es un lenguaje antiguo y que las FPU son un fenómeno relativamente reciente. Primero vi C en procesadores de 8 bits donde era mucho trabajo hacer aritmética de enteros de 32 bits. Muchas de estas implementaciones ni siquiera tener ¡una biblioteca matemática de punto flotante disponible!

Incluso en las primeras máquinas 68000 (Mac, Atari ST, Amiga), los coprocesadores de punto flotante a menudo eran complementos costosos.

Para hacer todas esas matemáticas de punto flotante, necesitabas una biblioteca bastante grande. Y las matemáticas iban a ser lentas. Entonces rara vez usaste flotadores. Intentaste hacer todo con números enteros o números enteros escalados. Cuando tuviste que incluir math.h, apretaste los dientes. A menudo, escribiría sus propias aproximaciones y tablas de búsqueda para evitarlo.

Las compensaciones existieron durante mucho tiempo. A veces había paquetes matemáticos de la competencia llamados “fastmath” o similares. ¿Cuál es la mejor solución para las matemáticas? ¿Cosas realmente precisas pero lentas? ¿Impreciso pero rápido? ¿Tablas grandes para funciones trigonométricas? No fue hasta que se garantizó que los coprocesadores estuvieran en la computadora que la mayoría de las implementaciones se hicieron obvias. Me imagino que hay algún programador en algún lugar ahora mismo, trabajando en un chip integrado, tratando de decidir si incorporar la biblioteca matemática para manejar algún problema matemático.

Por eso las matemáticas no eran estándar. Muchos o tal vez la mayoría de los programas no usaban un solo flotador. Si las FPU siempre hubieran existido y los flotadores y los dobles siempre hubieran sido baratos para operar, sin duda habría habido un “stdmath”.

  • Je, estoy usando aproximaciones de Pade para (1+x)^y en Java, en una PC de escritorio. Log, exp y pow siguen siendo lentos.

    – quant_dev

    24 de junio de 2009 a las 6:23

  • Buen punto. Y he visto aproximaciones para sin() en complementos de audio.

    – Nosredna

    24 de junio de 2009 a las 16:03

  • Esto explica por qué libm no está vinculado de forma predeterminada, pero las matemáticas sí estándar de C89 y antes de eso, K&R había de facto lo estandarizó, por lo que su comentario “stdmath” no tiene sentido.

    – Fred Foo

    14 de noviembre de 2011 a las 9:36

  • @FredFoo Se estandarizaron los tipos y las interfaces, pero no las implementaciones. Creo que Nosredna se refiere a una biblioteca matemática estándar.

    –Tim Bird

    22 de enero de 2020 a las 18:57

avatar de usuario
R.. GitHub DEJAR DE AYUDAR A ICE

Por ridícula práctica histórica que nadie está dispuesto a arreglar. La consolidación de todas las funciones requeridas por C y POSIX en un solo archivo de biblioteca no solo evitaría que esta pregunta se hiciera una y otra vez, sino que también ahorraría una cantidad significativa de tiempo y memoria al vincular dinámicamente, ya que cada .so El archivo vinculado requiere las operaciones del sistema de archivos para ubicarlo y encontrarlo, y algunas páginas para sus variables estáticas, reubicaciones, etc.

Una implementación donde todas las funciones están en una biblioteca y el -lm, -lpthread, -lrtetc. las opciones son todas no-ops (o enlace para vaciar .a archivos) es perfectamente compatible con POSIX y ciertamente preferible.

Nota: estoy hablando de POSIX porque C en sí mismo no especifica nada sobre cómo se invoca el compilador. Por lo tanto, solo puede tratar gcc -std=c99 -lm como la forma específica de implementación en la que se debe invocar al compilador para un comportamiento conforme.

  • +1 por señalar que POSIX no requiere que existan bibliotecas libm, libc y librt separadas. Como ejemplo, en Mac OS todo está ubicado en un solo libSystem (que también incluye libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc y librpcsvc).

    – F’x

    5 de enero de 2011 a las 20:38

  • –1 por especular sobre el impacto de la búsqueda en la biblioteca en el rendimiento sin respaldarlo con un enlace o números. “Perfil. No especules”

    – F’x

    5 de enero de 2011 a las 20:39

  • Esto no es especulación. No tengo ningún artículo publicado, pero yo mismo hice todas las mediciones y la diferencia es enorme. Solo usa strace con una de las opciones de tiempo para ver cuánto tiempo de inicio se dedica a la vinculación dinámica, o comparar la ejecución ./configure en un sistema en el que todas las utilidades estándar están vinculadas estáticamente frente a uno en el que están vinculadas dinámicamente. Incluso los principales desarrolladores de aplicaciones de escritorio e integradores de sistemas son conscientes de los costos de la vinculación dinámica; es por eso que existen cosas como prelink. Estoy seguro de que puede encontrar puntos de referencia en algunos de esos documentos.

    – R.. GitHub DEJA DE AYUDAR A ICE

    5 de enero de 2011 a las 21:59

  • @FX: No sé por qué olvidé mencionar esto antes: strace -tt le mostrará fácilmente el tiempo dedicado a la vinculación dinámica. No es lindo. Y en Linux, inspeccionando /proc/sys/smaps le mostrará la sobrecarga de memoria de las bibliotecas adicionales.

    – R.. GitHub DEJA DE AYUDAR A ICE

    2 abr 2011 a las 19:24

  • @TimBird: Gran parte de esa respuesta parece presuponer, incorrectamente, que vincular una biblioteca extrajo todo de ella, en lugar de solo las funciones (en la granularidad de la unidad de traducción, pero históricamente se dividieron correctamente en funciones individuales) que usa.

    – R.. GitHub DEJA DE AYUDAR A ICE

    22 de enero de 2020 a las 22:13


avatar de usuario
efímero

Las funciones en stdlib.h y stdio.h tener implementaciones en libc.so (o libc.a para la vinculación estática), que está vinculado a su ejecutable de forma predeterminada (como si -lc fueron especificados). GCC puede ser instruido para evitar este enlace automático con el -nostdlib o -nodefaultlibs opciones

Las funciones matemáticas en math.h tener implementaciones en libm.so (o libm.a para enlaces estáticos), y libm no está vinculado de forma predeterminada. Hay razones históricas para esto. libm/libc split, ninguno de ellos muy convincente.

Curiosamente, el tiempo de ejecución de C++ libstdc++ requiere libmpor lo que si compila un programa C++ con GCC (g++), obtendrá automáticamente libm vinculado en

  • Esto no tiene nada que ver con Linux, ya que era común mucho antes de Linux. Sospecho que tiene algo que ver con tratar de minimizar el tamaño del ejecutable, ya que hay muchos programas que no necesitan funciones matemáticas.

    –David Thornley

    23 de junio de 2009 a las 17:35

  • En los sistemas antiguos, si las funciones matemáticas estaban contenidas en libc, la compilación de todos los programas sería más lenta, los ejecutables de salida serían más grandes y el tiempo de ejecución requeriría más memoria, sin ningún beneficio para la mayoría programas que no utilizan estas funciones matemáticas en absoluto. En estos días tenemos un buen soporte para bibliotecas compartidas, e incluso cuando se vinculan estáticamente, las bibliotecas estándar están configuradas para que el código no utilizado se pueda descartar, por lo que ninguna de estas son buenas razones.

    – efímero

    23 de junio de 2009 a las 17:38

  • @ephemient Incluso en los viejos tiempos, la vinculación a una biblioteca no extraía todo el contenido de la biblioteca al ejecutable. Los enlazadores, aunque son una tecnología a menudo ignorada, históricamente han sido bastante eficientes.

    luego

    23 de junio de 2009 a las 17:43

  • @ephemient Además, las bibliotecas compartidas han existido por más tiempo de lo que piensas. Fueron inventados en la década de 1950, no en la década de 1980.

    luego

    23 de junio de 2009 a las 17:46

  • Supongo que al final del día lo que estamos viendo no es más que el conservadurismo de GCC: “siempre ha funcionado así”. Ojalá aplicaran el mismo razonamiento a sus extensiones de compilador.

    luego

    23 de junio de 2009 a las 17:59

es un error No debería tener que especificar explícitamente -lm ya no. Quizás si suficientes personas se quejan de eso, se arreglará. (No creo seriamente en esto, ya que los mantenedores que están perpetuando la distinción son evidentemente muy terco, pero puedo esperar.)

avatar de usuario
Saptarshi das

A todas las bibliotecas les gusta stdio.h y stdlib.h tener su implementación en libc.so o libc.a y ser vinculado por el enlazador de forma predeterminada. las bibliotecas para libc.so se vinculan automáticamente durante la compilación y se incluyen en el archivo ejecutable.

Pero math.h tiene sus implementaciones en libm.so o libm.a que está separado de libc.so y no se vincula de forma predeterminada y debe vincularlo manualmente mientras compila su programa en gcc mediante el uso -lm bandera.

El equipo gnu gcc lo diseñó para estar separado de los otros archivos de encabezado, mientras que los otros archivos de encabezado se vinculan de manera predeterminada, pero el archivo math.h no.

Aquí lea el punto 14.3, puede leerlo todo si lo desea:
Razón por la cual es necesario vincular math.h

Mira este artículo: ¿Por qué tenemos que vincular math.h en gcc?

Echa un vistazo al uso:
usando la biblioteca

  • Esto ya se ha dicho aquí en otras respuestas. Y esto ni siquiera responde la pregunta. La pregunta es por qué libm no está vinculado de forma predeterminada.

    – bolov

    26 de noviembre de 2020 a las 4:51

  • Significaba que math.h es un archivo de biblioteca escrito por separado en libm.so, mientras que para los otros archivos de encabezado está en libc.so, mientras que otros archivos de encabezado se vinculan automáticamente, pero es necesario vincular math.h manualmente agregando: soy bandera

    – Saptarshi das

    26 de noviembre de 2020 a las 11:02

  • Todos son parte de la biblioteca estándar. La pregunta es por qué no están todos vinculados por defecto. “Porque así es como lo diseñó el equipo de gcc” es una respuesta pobre. La pregunta era cuál es la razón. Y aquí hay excelentes respuestas que detallan las razones históricas. Su edición mejora su respuesta, pero aún no veo qué valor agrega sobre todas las otras respuestas aquí.

    – bolov

    26 de noviembre de 2020 a las 13:19

Tenga en cuenta que -lm Es posible que no siempre sea necesario especificarlo, incluso si usa algunas funciones matemáticas de C.

Por ejemplo, el siguiente programa simple:

#include <stdio.h>
#include <math.h>

int main() {

    printf("output: %f\n", sqrt(2.0));
    return 0;
}

se puede compilar y ejecutar correctamente con el siguiente comando:

gcc test.c -o test

Probado en gcc 7.5.0 (en Ubuntu 16.04) y gcc 4.8.0 (en CentOS 7).

La publicación aquí da algunas explicaciones:

Las funciones matemáticas a las que llama se implementan mediante funciones integradas del compilador

Ver también:

  • Esto ya se ha dicho aquí en otras respuestas. Y esto ni siquiera responde la pregunta. La pregunta es por qué libm no está vinculado de forma predeterminada.

    – bolov

    26 de noviembre de 2020 a las 4:51

  • Significaba que math.h es un archivo de biblioteca escrito por separado en libm.so, mientras que para los otros archivos de encabezado está en libc.so, mientras que otros archivos de encabezado se vinculan automáticamente, pero es necesario vincular math.h manualmente agregando: soy bandera

    – Saptarshi das

    26 de noviembre de 2020 a las 11:02

  • Todos son parte de la biblioteca estándar. La pregunta es por qué no están todos vinculados por defecto. “Porque así es como lo diseñó el equipo de gcc” es una respuesta pobre. La pregunta era cuál es la razón. Y aquí hay excelentes respuestas que detallan las razones históricas. Su edición mejora su respuesta, pero aún no veo qué valor agrega sobre todas las otras respuestas aquí.

    – bolov

    26 de noviembre de 2020 a las 13:19

Hay una discusión exhaustiva sobre la vinculación a bibliotecas externas en Introducción a GCC: vinculación con bibliotecas externas. Si una biblioteca es miembro de las bibliotecas estándar (como stdio), entonces no necesita especificar al compilador (realmente el enlazador) para vincularlas.

EDITAR: después de leer algunas de las otras respuestas y comentarios, creo que el referencia libc.a y la referencia libm que vincula a ambos tienen mucho que decir sobre por qué los dos están separados.

Tenga en cuenta que muchas de las funciones en ‘libm.a’ (la biblioteca matemática) están definidas en ‘math.h’ pero no están presentes en libc.a. Algunas lo son, lo que puede resultar confuso, pero la regla general es esta: la biblioteca C contiene aquellas funciones que ANSI dicta que deben existir, por lo que no necesita el -lm si solo usa funciones ANSI. Por el contrario, ‘libm.a’ contiene más funciones y admite funciones adicionales, como la devolución de llamada de matherr y el cumplimiento de varios estándares alternativos de comportamiento en caso de errores de FP. Ver la sección libm, para más detalles.

  • Lo que no responde a la pregunta de por qué tiene que vincular las bibliotecas de coincidencias por separado. Obviamente, desea tener que vincular las bibliotecas OpenGL por separado, pero podría decirse que las bibliotecas matemáticas son generalmente útiles.

    –David Thornley

    23 de junio de 2009 a las 17:33

  • @David: Tienes razón. No me quedó claro a partir de la pregunta que esta era la parte sobre la que preguntaba el OP. Estaba editando mi respuesta como comentaste.

    – Bill el lagarto

    23 de junio de 2009 a las 17:45

  • Sé la razón por la que compilé un programa que usa el sqrt función y funciona sin incluir la biblioteca a través de -lm. ¡Gracias!

    – L_K

    1 de junio de 2017 a las 3:04

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad