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


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>, usando -lm con gcc, por ejemplo:

gcc test.c -o test -lm

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

Author: Chris, 2009-06-23

9 answers

Las funciones en stdlib.h y stdio.h tienen implementaciones en libc.so (o libc.a para el enlace estático), que está vinculado a su ejecutable por defecto (como si se especificara -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. Hay razones históricas para esto libm/libc split, ninguno de ellos muy convincente.

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

 201
Author: ephemient,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-09 06:28:33

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

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

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

Las compensaciones existieron durante mucho tiempo. A veces había paquetes matemáticos que competían llamados "fastmath" o algo así. ¿Cuál es la mejor solución para las matemáticas? Muy precisa pero slow cosas? ¿Inexacta pero rápida? ¿Grandes mesas para funciones trigonométricas? Se no fue hasta que se garantizó que los coprocesadores estuvieran en el equipo que la mayoría de las implementaciones se hicieron obvias. Me imagino que hay algún programador por ahí en algún lugar ahora mismo, trabajando en un chip integrado, tratando de decidir si traer la biblioteca de matemáticas 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 utilizan un solo flotador. Si las FPU siempre habían existido y los flotadores y los dobles siempre eran baratos para operar, no dudo que hubiera habido un "stdmath".

 64
Author: Nosredna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 17:47:51

Se da una explicación aquí :

Así que si su programa está usando funciones matemáticas e incluyendo math.h, entonces necesita vincular explícitamente la biblioteca matemática pasando la bandera -lm. La razón de esta separación particular es que los matemáticos son muy quisquillosos acerca de la forma en que sus matemáticas se está computando y pueden querer utilizar su propia implementación de las funciones matemáticas en lugar de la implementación estándar. Si las funciones matemáticas se agruparan en libc.a no sería posible hacer eso.

[Editar]

No estoy seguro de estar de acuerdo con esto, sin embargo. Si usted tiene una biblioteca que proporciona, por ejemplo, sqrt(), y la pasa antes de la biblioteca estándar, un enlazador Unix tomará su versión, ¿verdad?

 25
Author: Bastien Léonard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 19:45:39

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 cabecera estándar. Solo para agregar a esto, de acuerdo con " An Introduction to GCC ", el comando enlazador para un programa 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 enlaza la biblioteca C.

 5
Author: ardsrk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 18:13:08

Hay una discusión exhaustiva sobre el enlace a bibliotecas externas en Una Introducción a GCC - Enlace 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 libc .una referencia y la referencia libm que enlaza a ambas tienen mucho que decir sobre por qué las dos son separado.

Tenga en cuenta que muchas de las funciones en 'libm.a '(la biblioteca de matemáticas) se definen en ' matemáticas.h ' pero no están presentes en libc.a. Algunas son, lo que puede ser confuso, pero la regla general es esta the la biblioteca C contiene aquellas funciones que ANSI dicta que deben existir, por lo que no necesita el-lm si solo usa funciones ANSI. En contraste, `libm.a ' contiene más funciones y admite funciones adicionales, como la devolución de llamada matherr y el cumplimiento de varias alternativas normas de comportamiento en caso de errores FP. Vea la sección libm, para más detalles.

 4
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 17:36:22

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

Las implementaciones de funciones matemáticas están en un archivo libm separado al que no está vinculado de forma predeterminada, por lo que debe especificar it-lm. Por cierto, no hay relación entre esos archivos de encabezado y archivos de biblioteca.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 17:12:39

Creo que es algo arbitrario. Debe dibujar una línea en algún lugar (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.

EDIT: (de mis propios comentarios): Creo que gcc hace esto para mantener la compatibilidad hacia atrás con el cc original. Mi conjetura de por qué cc hace esto es debido al tiempo de compilación cc cc fue escrito para máquinas con mucho menos poder del que tenemos ahora. Muchos programas no tienen matemáticas de coma flotante y probablemente tomaron todas las bibliotecas que no se usaban comúnmente de la forma predeterminada. Supongo que el tiempo de compilación del sistema operativo UNIX y las herramientas que lo acompañan fueron la fuerza impulsora.

 3
Author: Lou Franco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 17:24:41

Si pongo stdlib.h o stdio.h, no tengo el enlace, pero tengo que vincular al compilar:

stdlib.h, stdio.h son los archivos de cabecera. Usted los incluye para su conveniencia. Solo pronostican qué símbolos estarán disponibles si se 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 obtener acceso a todas las funciones matemáticas.

Además, no tiene que enlazar contra libm si no usa sus funciones, incluso si hace un #include <math.h> que es solo un paso informativo para usted, para el compilador sobre los símbolos.

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

 3
Author: Adrian Panasiuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 17:44:12

Yo supongo que es una manera de hacer que las aplicaciones que no lo utilizan en absoluto funcionan un poco mejor. Esto es lo que pienso.

Los sistemas operativos X86 (y me imagino que otros) necesitan almacenar el estado FPU en el interruptor 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, probablemente haya algún código básico en la biblioteca de matemáticas que establecerá la FPU en un estado base sano cuando la biblioteca esté cargar.

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 FPU, lo que hace que los cambios de contexto sean un poco más eficientes.

Solo una suposición.

EDIT: en respuesta a algunos de los comentarios, la misma premisa base todavía se aplica a los casos que no son FPU (la premisa es que era hacer que las aplicaciones que no utilizan libm funcionen un poco mejor).

Por ejemplo, si hay un soft-FPU que era likley en los primeros días de C. Entonces tener libm separado podría evitar que una gran cantidad de código grande (y lento si se usaba) se vinculara innecesariamente.

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

 2
Author: Evan Teran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-23 18:07:16