Pregunta

Si me incluyen <stdlib.h> o <stdio.h> en un programa en C no tengo que vincular estas al compilar pero tengo que enlace 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 vincula explícitamente la biblioteca matemática, pero no las otras bibliotecas?

¿Fue útil?

Solución

Las funciones en stdlib.h y stdio.h tienen implementaciones en libc.so (o libc.a para la vinculación estática), que está vinculado a tu ejecutable por defecto (como si -lc se han especificado).GCC puede ser instruidos para evitar este enlace automático con la -nostdlib o -nodefaultlibs opciones.

Las funciones matemáticas en math.h tienen implementaciones en libm.so (o libm.a para la vinculación estática), y libm no se vincula de forma predeterminada.Hay razones históricas para este libm/libc split, ninguno de ellos muy convincente.

Curiosamente, el C++ runtime libstdc++ requiere libm, por lo que si se compila un programa de C++ con GCC (g++), obtendrá automáticamente libm linked in.

Otros consejos

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ía sus propias aproximaciones y tablas de búsqueda para evitarlo.

Las compensaciones existieron durante mucho tiempo. Algunas veces había paquetes matemáticos competitivos llamados & Quot; fastmath & Quot; o tal ¿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 volvieron obvias. 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.

Es por eso que 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 un & Quot; stdmath & Quot ;.

Debido a una 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 implementación donde todas las funciones están en una biblioteca y las opciones -lm, -lpthread, -lrt, etc. son todas no operativas (o enlace a archivos .a vacíos) es perfectamente compatible con POSIX y ciertamente preferible.

Nota: estoy hablando de POSIX porque C 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 en la que debe invocarse el compilador para un comportamiento conforme.

Porque time() y algunas otras funciones builtin definido en la librería de C (libc en sí mismo y GCC siempre enlaces a libc a menos que utilice el -ffreestanding opción de compilación.Sin embargo matemáticas de las funciones de vivir en libm que no está implícitamente ligado por gcc.

Se da una explicación aquí :

  

Entonces, si su programa usa funciones matemáticas e incluye 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 exigentes con la forma en que se calculan sus matemáticas y pueden querer usar 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]

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?

Como dijo ephemient, 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 & Quot; Una introducción a GCC " el comando de enlace para un " Hello World " El programa 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 une la biblioteca C.

Hay una discusión exhaustiva sobre la vinculación a bibliotecas externas en Una 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 el libc.a referencia y la referencia de libm a la que enlaza 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. Algunos son confusos, pero la regla general es esta: la biblioteca C contiene aquellas funciones que ANSI dicta que deben existir, de modo que no necesita el -lm si solo usa funciones ANSI. En contraste, 'libm.a' contiene más funciones y admite funcionalidades adicionales, como la devolución de llamada de matherr y el cumplimiento de varios estándares de comportamiento alternativos en caso de errores de FP. Vea la sección libm, para más detalles.

Creo que es algo 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: (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.

  

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. 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.

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

Además, no tiene que vincular 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.

libc, <=> se refieren a las funciones disponibles en <=>, que siempre están vinculadas para que el usuario no tenga que hacerlo él mismo.

stdio es parte de la biblioteca estándar de C que, de forma predeterminada, gcc se vinculará contra.

Las implementaciones de la función matemática están 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.

Supongo adivinar que es una forma de hacer que las aplicaciones que no lo usan funcionen 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 intenta 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 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 un poco más eficientes.

Solo una suposición.

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 era para hacer aplicaciones que no hicieron que el uso de libm funcione ligeramente 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 un gran 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ía los tamaños de los ejecutables y los tiempos de compilación reducidos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top