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

Si o en un progtwig C, no es necesario que los vincule al comstackr, pero sí tengo que vincularlo con , usando -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 matemática, pero no las otras bibliotecas?

Las funciones en stdlib.h y stdio.h tienen implementaciones en libc.so (o libc.a para enlaces estáticos), que están vinculadas en su ejecutable por defecto (como si se -lc especificado -lc ). Se puede indicar a GCC que evite este enlace automático con las opciones -nostdlib o -nodefaultlibs .

Las funciones matemáticas en math.h tienen implementaciones en libm.so (o libm.a para enlaces estáticos), y libm no está enlazado por defecto. Existen razones históricas para esta libm / libc , ninguna de ellas muy convincente.

Curiosamente, el tiempo de ejecución de C ++ libstdc++ requiere libm , por lo que si comstack un progtwig C ++ con GCC ( g++ ), obtendrá automáticamente el libm en.

Recuerde que C es un lenguaje antiguo y que las FPU son un fenómeno relativamente reciente. La primera vez que vi C en procesadores de 8 bits fue mucho trabajo hacer incluso la aritmética de enteros de 32 bits. ¡Muchas de estas implementaciones ni siquiera tenían una biblioteca matemática de punto flotante disponible!

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

Para hacer todo ese cálculo de coma flotante, necesitabas una biblioteca bastante grande. Y las matemáticas iban a ser lentas Entonces, rara vez usabas carrozas. Intentó hacer todo con enteros o enteros escalados. Cuando tenía que incluir math.h, apretaba los dientes. A menudo, debe escribir sus propias aproximaciones y tablas de búsqueda para evitarlo.

Las compensaciones existieron por un largo tiempo. A veces había paquetes de matemáticas competitivos llamados “fastmath” o similares. ¿Cuál es la mejor solución para matemáticas? ¿Cosas realmente precisas pero lentas? ¿Inexacto pero rápido? ¿Grandes tablas para las funciones trigonométricas? No fue sino hasta que se garantizó que los coprocesadores estarían en la computadora que la mayoría de las implementaciones se volvieron obvias. Me imagino que hay algún progtwigdor por ahí en algún lugar en este momento, trabajando en un chip incrustado, tratando de decidir si traer la biblioteca matemática para manejar algún problema matemático.

Es por eso que las matemáticas no eran estándar . Muchos o tal vez la mayoría de los progtwigs no usaron un solo flotador. Si las FPU siempre han existido y las flotantes y los dobles siempre son baratos para operar, sin duda habría habido un “stdmath”.

Una explicación se da aquí :

Entonces, si su progtwig usa funciones matemáticas e incluye math.h , entonces necesita vincular explícitamente la biblioteca matemática pasando el indicador -lm . La razón de esta separación particular es que los matemáticos son muy exigentes con la forma en que se calculan sus matemáticas y es posible que quieran usar su propia implementación de las funciones matemáticas en lugar de la implementación estándar. Si las funciones matemáticas estuvieran agrupadas en libc.a , no sería posible hacer eso.

[Editar]

Aunque no estoy seguro de estar de acuerdo con esto. Si tiene una biblioteca que proporciona, por ejemplo, sqrt() , y la pasa ante la biblioteca estándar, un vinculador de Unix tomará su versión, ¿verdad?

Como dijo ephemient, la biblioteca de C libc está vinculada por defecto y esta biblioteca contiene las implementaciones de stdlib.h, stdio.h y varios otros archivos de encabezado estándar. Solo para agregarlo, de acuerdo con ” Una introducción a GCC “, el comando del enlazador para un progtwig básico de “Hola mundo” en C es el siguiente:

 ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o -L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o 

Observe la opción -lc en la tercera línea que vincula la biblioteca C.

En An Introduction to GCC (Introducción a GCC) se establece un debate exhaustivo sobre cómo vincularse a bibliotecas externas . Vinculación con bibliotecas externas . Si una biblioteca es miembro de las bibliotecas estándar (como stdio), entonces no necesita especificar al comstackdor (realmente el vinculador) para vincularlas.

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

Tenga en cuenta que muchas de las funciones en ‘libm.a’ (la biblioteca matemática) se definen en ‘math.h’ pero no están presentes en libc.a. Algunos lo son, lo que puede confundir, pero la regla general es la siguiente: la biblioteca C contiene las funciones que ANSI dicta debe 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 callback matherr y el cumplimiento de varios estándares de comportamiento alternativos en caso de errores de FP. Ver la sección libm, para más detalles.

stdio es parte de la biblioteca C estándar que, por defecto, gcc enlazará.

Las implementaciones de la función matemática están en un archivo separado de libm que no está vinculado por defecto, por lo que debe especificarlo -lm. Por cierto, no hay relación entre esos archivos de encabezado y archivos de biblioteca.

Creo que es un poco arbitrario. Debe dibujar una línea en alguna parte (qué bibliotecas son predeterminadas y cuáles deben especificarse).

Te da la oportunidad de reemplazarlo por uno diferente que tenga las mismas funciones, pero no creo que sea muy común hacerlo.

EDITAR: (según mis propios comentarios): creo que gcc hace esto para mantener la compatibilidad con el cc original. Mi suposición de por qué cc hace esto es debido al tiempo de comstackción – cc fue escrito para máquinas con mucho menos poder que el que tenemos ahora. Muchos progtwigs no tienen matemática de punto flotante y probablemente tomaron todas las bibliotecas que no se usaban habitualmente para salir de la configuración predeterminada. Supongo que el tiempo de comstackción del sistema operativo UNIX y las herramientas que lo acompañan fueron la fuerza impulsora.

Si pongo stdlib.h o stdio.h, no tengo que vincularlos, pero tengo que vincular cuando compilo:

stdlib.h , stdio.h son los archivos de encabezado. Usted los incluye para su conveniencia. Solo pronostican qué símbolos estarán disponibles si enlaza en la biblioteca adecuada. Las implementaciones están en los archivos de la biblioteca, ahí es donde realmente viven las funciones.

Incluir math.h es solo el primer paso para acceder a todas las funciones matemáticas.

Además, no tiene que enlazar con libm si no usa sus funciones, incluso si hace un #include que es solo un paso informativo para usted, para el comstackdor sobre los símbolos.

stdlib.h , stdio.h refieren a las funciones disponibles en libc , que siempre están enlazadas para que el usuario no tenga que hacerlo él mismo.

Supongo que es una forma de hacer que las aplicaciones que no las usan rindan un poco mejor. Aquí está mi pensamiento sobre esto.

Los sistemas operativos x86 (y me imagino a otros) necesitan almacenar el estado de FPU en el cambio de contexto. Sin embargo, la mayoría de los sistemas operativos solo se molestan en guardar / restaurar este estado después de que la aplicación intente usar la FPU por primera vez.

Además de esto, es probable que haya algún código básico en la biblioteca matemática que establecerá la FPU en un estado base sano cuando se cargue la biblioteca.

Por lo tanto, si no enlaza ningún código matemático, nada de esto sucederá, por lo tanto, el sistema operativo no tiene que guardar / restaurar ningún estado de FPU, lo que hace que los cambios de contexto sean ligeramente más eficientes.

Sólo una suposición sin embargo.

EDITAR: en respuesta a algunos de los comentarios, la misma premisa básica todavía se aplica a los casos que no pertenecen a la FPU (la premisa es que era hacer que las aplicaciones que no hicieron que el uso de la libma funcionaran un poco mejor).

Por ejemplo, si hay una FPU blanda que era muy probable en los primeros días de C. Luego, separar una libm podría evitar que un código grande (y lento si se usara) se vincule innecesariamente.

Además, si solo hay enlaces estáticos disponibles, se aplica un argumento similar que mantendrá los tamaños de los ejecutables y los tiempos de comstackción.