Si j'inclus <stdlib.h>
ou <stdio.h>
dans un programme C, je n'ai pas à les lier lors de la compilation mais je dois me lier à <math.h>
, en utilisant -lm
avec gcc, par exemple:
gcc test.c -o test -lm
Quelle est la raison pour ça? Pourquoi dois-je lier explicitement la bibliothèque mathématique mais pas les autres bibliothèques?
la source
N'oubliez pas que C est un ancien langage et que les FPU sont un phénomène relativement récent. J'ai vu C pour la première fois sur des processeurs 8 bits où il y avait beaucoup de travail pour faire de l'arithmétique même sur 32 bits. Un grand nombre de ces mises en œuvre ne même pas avoir une bibliothèque de mathématiques à virgule flottante disponible!
Même sur les 68000 premières machines (Mac, Atari ST, Amiga), les coprocesseurs à virgule flottante étaient souvent des modules complémentaires coûteux.
Pour faire tout ce calcul en virgule flottante, vous aviez besoin d'une bibliothèque assez importante. Et les calculs allaient être lents. Vous avez donc rarement utilisé des flotteurs. Vous avez essayé de tout faire avec des entiers ou des entiers mis à l'échelle. Quand vous avez dû inclure math.h, vous avez serré les dents. Souvent, vous écriviez vos propres approximations et tables de recherche pour l'éviter.
Les compromis existaient depuis longtemps. Parfois, il y avait des packages mathématiques concurrents appelés "fastmath" ou autres. Quelle est la meilleure solution pour les mathématiques? Des trucs vraiment précis mais lents? Imprécis mais rapide? De grandes tables pour les fonctions trigonométriques? Ce n'est que lorsque les coprocesseurs ont été garantis dans l'ordinateur que la plupart des implémentations sont devenues évidentes. J'imagine qu'il y a un programmeur quelque part en ce moment, travaillant sur une puce intégrée, essayant de décider d'apporter la bibliothèque mathématique pour gérer un problème mathématique.
C'est pourquoi les mathématiques n'étaient pas standard . Beaucoup ou peut-être la plupart des programmes n'utilisaient pas un seul flottant. Si les FPU avaient toujours été là et que les flotteurs et les doubles étaient toujours bon marché, il y aurait sans aucun doute eu un "stdmath".
la source
libm
n'est pas lié par défaut, mais les mathématiques étaient standard depuis C89 et avant cela, K&R les avait standardisées de facto , donc votre remarque "stdmath" n'a pas de sens.À cause d'une pratique historique ridicule que personne ne veut réparer. La consolidation de toutes les fonctions requises par C et POSIX dans un seul fichier de bibliothèque éviterait non seulement de poser cette question à plusieurs reprises, mais permettrait également d'économiser beaucoup de temps et de mémoire lors de la liaison dynamique, car chaque
.so
fichier lié nécessite les opérations du système de fichiers pour le localiser et le trouver, et quelques pages pour ses variables statiques, délocalisations, etc.Une mise en œuvre où toutes les fonctions sont dans une bibliothèque et
-lm
,-lpthread
,-lrt
options , etc. sont tous pas d'habitation (ou lien vers vides.a
fichiers) est parfaitement conforme POSIX et certainement préférable.Remarque: je parle de POSIX parce que C lui-même ne spécifie rien sur la façon dont le compilateur est appelé. Ainsi, vous pouvez simplement considérer
gcc -std=c99 -lm
comme la manière spécifique à l'implémentation le compilateur doit être appelé pour un comportement conforme.la source
strace
une des options de synchronisation pour voir combien de temps de démarrage est consacré à la liaison dynamique, ou comparez l'exécution./configure
sur un système où tous les utilitaires standard sont liés statiquement à ceux où ils sont liés dynamiquement. Même les développeurs d'applications de bureau grand public et les intégrateurs de systèmes sont conscients des coûts de la liaison dynamique; c'est pourquoi des choses comme le pré-lien existent. Je suis sûr que vous pouvez trouver des repères dans certains de ces articles.-lm
d'être acceptée et les applications qui utilisent les interfaces mathématiques doivent utiliser-lm
, mais il peut être une option interne traitée (ou même ignoré) par la commande du compilateur, pas un fichier de bibliothèque réelle. Ou il peut simplement s'agir d'un.a
fichier vide si les interfaces sont dans la libc principale.strace -tt
vous montrera facilement le temps passé sur les liens dynamiques. Ce n'est pas joli. Et sous Linux, l'inspection/proc/sys/smaps
vous montrera la surcharge de mémoire des bibliothèques supplémentaires.Parce que
time()
et certaines autres fonctions sontbuiltin
définies dans la bibliothèque C (libc
) elle-même et GCC est toujours lié à libc sauf si vous utilisez l'-ffreestanding
option de compilation. Cependant, les fonctions mathématiques existent danslibm
lesquelles n'est pas implicitement lié par gcc.la source
Une explication est donnée ici :
[Éditer]
Je ne suis cependant pas sûr d'être d'accord avec cela. Si vous avez une bibliothèque qui fournit, disons,
sqrt()
et que vous la transmettez avant la bibliothèque standard, un éditeur de liens Unix prendra votre version, non?la source
sqrt
donne un programme au comportement indéfini.-lm
est totalement optionnel. Toutes les idéesIl y a une discussion approfondie sur la liaison à des bibliothèques externes dans Une introduction à GCC - Liaison avec des bibliothèques externes . Si une bibliothèque est membre des bibliothèques standard (comme stdio), vous n'avez pas besoin de spécifier au compilateur (vraiment l'éditeur de liens) pour les lier.
EDIT: Après avoir lu certaines des autres réponses et commentaires, je pense que la référence libc.a et la référence libm qu'elle relie aux deux ont beaucoup à dire sur la raison pour laquelle les deux sont séparés.
la source
sqrt
fonction et cela fonctionne sans inclure la bibliothèque via-lm
. Merci!Comme l'éphémient l'a dit, la bibliothèque C libc est liée par défaut et cette bibliothèque contient les implémentations de stdlib.h, stdio.h et plusieurs autres fichiers d'en-tête standard. Juste pour y ajouter, selon " An Introduction to GCC ", la commande de l'éditeur de liens pour un programme de base "Hello World" en C est comme ci-dessous:
Notez l'option -lc dans la troisième ligne qui relie la bibliothèque C.
la source
Je pense que c'est un peu arbitraire. Vous devez tracer une ligne quelque part (quelles bibliothèques sont par défaut et lesquelles doivent être spécifiées).
Cela vous donne la possibilité de le remplacer par un autre qui a les mêmes fonctions, mais je ne pense pas que ce soit très courant de le faire.
EDIT: (d'après mes propres commentaires): Je pense que gcc fait cela pour maintenir la compatibilité descendante avec le cc d'origine. J'imagine pourquoi cc fait cela à cause du temps de construction - cc a été écrit pour les machines avec beaucoup moins de puissance que nous avons maintenant. De nombreux programmes n'ont pas de calcul en virgule flottante et ils ont probablement pris toutes les bibliothèques qui n'étaient pas couramment utilisées par défaut. Je suppose que le temps de construction du système d'exploitation UNIX et des outils qui l'accompagnaient ont été la force motrice.
la source
stdlib.h
,stdio.h
sont les fichiers d'en-tête. Vous les incluez pour votre commodité. Ils prévoient uniquement les symboles qui deviendront disponibles si vous créez un lien dans la bibliothèque appropriée. Les implémentations sont dans les fichiers de la bibliothèque, c'est là que les fonctions vivent vraiment.L'inclusion
math.h
n'est que la première étape pour accéder à toutes les fonctions mathématiques.De plus, vous n'avez pas à vous lier
libm
si vous n'utilisez pas ses fonctions, même si vous effectuez une#include <math.h>
étape qui n'est qu'une information pour vous, pour le compilateur sur les symboles.stdlib.h
,stdio.h
reportez - vous aux fonctions disponibles danslibc
, qui se trouvent toujours liées afin que l'utilisateur n'ait pas à le faire lui-même.la source
stdio fait partie de la bibliothèque C standard avec laquelle, par défaut, gcc sera lié.
Les implémentations de la fonction mathématique se trouvent dans un fichier libm distinct qui n'est pas lié par défaut, vous devez donc le spécifier -lm. Soit dit en passant, il n'y a aucune relation entre ces fichiers d'en-tête et les fichiers de bibliothèque.
la source
Je suppose que c'est un moyen de rendre les applications qui ne l'utilisent pas du tout légèrement plus performantes. Voici ma réflexion à ce sujet.
Les systèmes d'exploitation x86 (et j'imagine que d'autres) doivent stocker l'état du FPU sur le changement de contexte. Cependant, la plupart des systèmes d'exploitation ne prennent la peine de sauvegarder / restaurer cet état qu'après que l'application a tenté d'utiliser le FPU pour la première fois.
En plus de cela, il y a probablement un code de base dans la bibliothèque mathématique qui mettra le FPU dans un état de base sain lorsque la bibliothèque est chargée.
Donc, si vous ne liez pas du tout de code mathématique, rien de tout cela ne se produira, par conséquent, le système d'exploitation n'a pas du tout à sauvegarder / restaurer l'état FPU, ce qui rend les changements de contexte légèrement plus efficaces.
Mais juste une supposition.
EDIT: en réponse à certains commentaires, la même prémisse de base s'applique toujours aux cas non FPU (la prémisse étant qu'il s'agissait de faire légèrement mieux les applications qui n'utilisaient pas libm).
Par exemple, s'il existe un soft-FPU qui était semblable aux premiers jours de C. Ensuite, avoir libm séparé pourrait empêcher beaucoup de code volumineux (et lent s'il était utilisé) d'être lié inutilement.
De plus, s'il n'y a que des liens statiques disponibles, un argument similaire s'applique, selon lequel les tailles exécutables et les temps de compilation seront réduits.
la source