Las funciones en stdlib.h
y stdio.h
tienen implementaciones en libc.so
(o libc.a
para enlace estático), que está vinculado a su ejecutable de forma predeterminada (como si -lc
se especificara). 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án vinculadas por defecto. Hay razones históricas para esto libm
/ libc
división, ninguna de ellas 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++
), se libm
vinculará automáticamente .
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 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 máquinas 68000 (Mac, Atari ST, Amiga), los coprocesadores de coma flotante a menudo eran complementos caros.
Para hacer todos esos cálculos de coma flotante, necesitabas una biblioteca bastante considerable. Y las matemáticas iban a ser lentas. Así que rara vez usabas flotadores. Intentaste hacer todo con enteros o enteros escalados. Cuando tenías que incluir matemáticas.h, apretabas 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 competitivos llamados "fastmath" o algo así. ¿Cuál es la mejor solución para las matemáticas? ¿Cosas realmente precisas pero lentas? ¿Inexacto pero rápido? Tablas grandes para funciones trigonométricas? No fue hasta que se garantizó que los coprocesadores estaban en la computadora que la mayoría de las implementaciones se hicieron evidentes. Me imagino que hay algún programador en algún lugar en este momento, trabajando en un chip incorporado, tratando de decidir si traer 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 usaron un solo flotador. Si las FPU siempre hubieran existido y los flotadores y los dobles fueran siempre baratos para operar, sin duda habría habido una "mala educación".
fuente
libm
no está vinculado por defecto, pero las matemáticas eran estándar desde C89 y antes de eso, K&R lo había estandarizado de facto , por lo que su comentario "stdmath" no tiene sentido.Debido a la práctica histórica ridícula 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
archivo vinculado requiere las operaciones del sistema de archivos para localizarlo y encontrarlo, y algunas páginas para sus variables estáticas, reubicaciones, etc.Una aplicación que todas las funciones están en una biblioteca y el
-lm
,-lpthread
,-lrt
, etc. opciones son todos los no-ops (o enlace a vacíos.a
archivos) está perfectamente conformes con POSIX y ciertamente preferible.Nota: estoy hablando de POSIX porque C en sí no especifica nada sobre cómo se invoca el compilador. Por lo tanto, puede tratar
gcc -std=c99 -lm
como la forma específica de implementación que se debe invocar al compilador para un comportamiento conforme.fuente
strace
con una de las opciones de tiempo para ver cuánto tiempo de inicio se dedica a la vinculación dinámica, o compare la ejecución./configure
en un sistema donde todas las utilidades estándar están vinculadas estáticamente versus una donde 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; Por eso existen cosas como el preenlace. Estoy seguro de que puede encontrar puntos de referencia en algunos de esos documentos.-lm
que se acepte y las aplicaciones que utilizan las interfaces de matemáticas debe utilizar-lm
, pero puede ser una opción interna manejada (o incluso ignorado) por el comando del compilador, no un archivo de biblioteca real. O simplemente puede ser un.a
archivo vacío si las interfaces están en la biblioteca principal.strace -tt
le mostrará fácilmente el tiempo dedicado a la vinculación dinámica. No es lindo. Y en Linux, la inspección/proc/sys/smaps
le mostrará la sobrecarga de memoria de bibliotecas adicionales.Porque
time()
y algunas otras funciones estánbuiltin
definidas en la biblioteca C (libc
) y GCC siempre se vincula a libc a menos que use la-ffreestanding
opción de compilación. Sin embargo, las funciones matemáticas viven en laslibm
que no está implícitamente vinculado por gcc.fuente
Aquí se da una explicación :
[Editar]
Sin embargo, no estoy seguro de estar de acuerdo con esto. Si tiene una biblioteca que proporciona, digamos,
sqrt()
y la pasa antes que la biblioteca estándar, un enlazador de Unix tomará su versión, ¿verdad?fuente
sqrt
resultado resultados en un programa con comportamiento indefinido.-lm
es totalmente opcional. Alguna ideaHay 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 vinculador) para vincularlas.
EDITAR: Después de leer algunas de las otras respuestas y comentarios, creo que la referencia libc.a y la referencia libm a la que enlaza ambas tienen mucho que decir sobre por qué las dos están separadas.
fuente
sqrt
función y funciona sin incluir la biblioteca a través de-lm
. ¡Gracias!Como ephemient dijo, la biblioteca de C libc está vinculada de forma predeterminada y esta biblioteca contiene las implementaciones de stdlib.h, stdio.h y varios otros archivos de encabezado estándar. Solo para agregarle, de acuerdo con " Una introducción a GCC ", el comando de enlace para un programa básico "Hello World" en C es el siguiente:
Observe la opción -lc en la tercera línea que une la biblioteca C.
fuente
Creo que es algo arbitrario. Debe dibujar una línea en alguna parte (qué bibliotecas son predeterminadas y cuáles deben especificarse).
Le da la oportunidad de reemplazarlo por uno diferente que tenga las mismas funciones, pero no creo que sea muy común hacerlo.
EDITAR: (de mis propios comentarios): Creo que gcc hace esto para mantener la compatibilidad con el cc original. Supongo por qué cc hace esto es por el tiempo de construcción: cc fue escrito para máquinas con mucha menos potencia que la que tenemos ahora. Muchos programas no tienen matemática de punto flotante y probablemente tomaron todas las bibliotecas que no se usaban comúnmente de manera predeterminada. Supongo que el tiempo de compilación del sistema operativo UNIX y las herramientas que lo acompañan fueron la fuerza impulsora.
fuente
stdlib.h
,stdio.h
son los archivos de encabezado. Los incluye para su conveniencia. Solo pronostican qué símbolos estarán disponibles si se vincula en la biblioteca adecuada. Las implementaciones están en los archivos de la biblioteca, ahí es donde realmente viven las funciones.Incluso
math.h
es solo el primer paso para obtener acceso a todas las funciones matemáticas.Además, no tiene que vincularse
libm
si no usa sus funciones, incluso si hace un#include <math.h>
que es solo informativo para usted, para el compilador sobre los símbolos.stdlib.h
,stdio.h
consulte las funciones disponibles enlibc
, que siempre están vinculadas para que el usuario no tenga que hacerlo él mismo.fuente
stdio es parte de la biblioteca estándar de C que, por defecto, gcc enlazará.
Las implementaciones de la función matemática se encuentran en un archivo libm separado que no está vinculado de forma predeterminada, por lo que debe especificarlo -lm. Por cierto, no hay relación entre esos archivos de encabezado y los archivos de la biblioteca.
fuente
Yo supongo que es una manera de hacer que las aplicaciones que no utilizan en absoluto realizar un poco mejor. Aquí está mi pensamiento sobre esto.
Los sistemas operativos x86 (e imagino que otros) necesitan almacenar el estado de la 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, probablemente 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.
Entonces, si no vincula 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 un poco más eficientes.
Solo 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 son de FPU (la premisa es que fue para hacer que las aplicaciones que no hicieron que el uso de libm funcione un poco mejor).
Por ejemplo, si hay una FPU suave que era probable en los primeros días de C. Entonces tener libm por separado podría evitar que muchos códigos grandes (y lentos si se usaran) se vinculen innecesariamente.
Además, si solo hay enlaces estáticos disponibles, se aplica un argumento similar que mantendría los tamaños ejecutables y los tiempos de compilación reducidos.
fuente