Utilisation des bibliothèques à virgule flottante
Il existe deux types de nombres avec lesquels vous travaillez en C : entier (int, short, long,...) et virgule flottante (float, double). Le microprocesseur de votre ordinateur est configuré pour gérer facilement les valeurs entières, mais il faut plus de temps et d'efforts pour gérer les valeurs à virgule flottante. Cependant, la famille de processeurs iAPx86 a une famille correspondante de coprocesseurs mathématiques, le 8087 et le 80287. Le 8087 et le 80287 (tous deux que nous appelons ici «le 8087» ou «le coprocesseur») sont des processeurs numériques matériels spéciaux pouvant être installés sur votre PC. Ils exécutent très rapidement les instructions en virgule flottante. Si vous utilisez beaucoup la virgule flottante, vous aurez probablement besoin d'un coprocesseur. Le microprocesseur de votre ordinateur s'interface avec le 8087 via des interruptions spéciales. Le Turbo C est conçu pour vous aider à adapter votre programme à votre ordinateur et à vos besoins.
- Si vous n'avez pas du tout besoin d'utiliser des valeurs à virgule flottante, vous pouvez le dire au compilateur.
- Si vous avez besoin d'utiliser des valeurs à virgule flottante mais que votre ordinateur n'a pas de coprocesseur mathématique (8087/80287), vous pouvez dire à Turbo C de se lier à des routines spéciales pour donner l'impression que vous en avez un. Dans ce cas, si votre programme est exécuté sur un système avec un coprocesseur, la puce est automatiquement utilisée (et votre programme s'exécute beaucoup plus rapidement).
- Si vous écrivez des programmes uniquement pour des systèmes ayant un coprocesseur mathématique, vous pouvez demander au compilateur Turbo C de produire du code utilisant toujours la puce 8087/80287.
Émulation de la puce 8087/80287
Que faire si vous souhaitez utiliser la virgule flottante, mais que votre ordinateur ne dispose pas d'un coprocesseur mathématique ? Ou que se passe-t-il si vous devez écrire un programme pour des ordinateurs en ayant ou non ? Ne vous inquiéter pas; le Turbo C gère bien cette situation. Avec l'option d'émulation, le compilateur générera du code comme si le 8087 était présent, mais se liera dans la bibliothèque d'émulation (EMU.LIB). Lorsque le programme s'exécute, il utilisera le 8087 s'il est présent; si aucun coprocesseur n'est présent au moment de l'exécution, le programme utilisera un logiciel spécial émulant le 8087. La bibliothèque d'émulation fonctionne comme ceci :
- Lorsque votre programme commence à s'exécuter, le code de démarrage C déterminera si un 8087 est présent ou non.
- Si le coprocesseur est là, le programme permettra aux interruptions spéciales pour le 8087 d'être transmises directement à la puce 8087.
- Si le coprocesseur n'est pas là, le programme provoque l'interception des interruptions et le détournement vers les routines d'émulation.
Supposons que vous modifiez MONRATIO.C pour ressembler à ceci :
Si vous utilisez TC (la version de l'interface utilisateur), vous devez aller dans le menu Options, sélectionner Compiler, sélectionner Code generation, puis sélectionner l'élément Floating-point jusqu'à ce que le champ suivant indique Emulation. Lorsque vous compilez et liez votre programme, le Turbo C sélectionne automatiquement les options et bibliothèques appropriées pour vous. Si vous utilisez TCC (le compilateur autonome), votre ligne de commande devrait ressembler à ceci :
tcc -mX monratio |
Si vous liez manuellement le code résultant, vous devez spécifier à la fois la bibliothèque mathématique appropriée (en fonction de la taille du modèle) et le fichier EMU.LIB. L'option d'émulation (-f) est activée par défaut, vous n'avez donc pas besoin de la donner à moins que votre fichier TURBOC.CFG ne contienne l'un des autres commutateurs à virgule flottante (-f- ou -f87). Ainsi, votre appel de TLINK devrait ressembler à la commande suivante :
tlink lib\c0X monratio, monratio, monratio, lib\emu.lib lib\mathX.lib lib\cX.lib |
où X est une lettre indiquant la bibliothèque de modèles appropriée. La commande tlink est donnée sur une seule ligne. Rappelez-vous également que l'ordre des bibliothèques est très important.
Utilisation de la puce coprocesseur mathématique 8087/80287
Si vous êtes absolument sûr que votre programme ne fonctionnera que sur des systèmes dotés d'une puce 8087 ou 80287, vous pouvez créer des programmes tirant parti de cette puce. Dans le même temps, les fichiers .EXE résultants seront plus petits, car Turbo C n'aura pas à inclure les routines d'émulation 8087 (EMU.LIB). Si vous utilisez TC (la version de l'interface utilisateur), vous devez aller dans le menu Options, sélectionner Compiler, sélectionner Code generation, puis sélectionner l'élément Floating point jusqu'à ce que le champ suivant indique 8087/80287. Lorsque vous compilez et liez votre programme, le Turbo C sélectionne automatiquement les options et bibliothèques appropriées pour vous. Si vous utilisez TCC (le compilateur autonome), vous devez utiliser l'option -f87 sur votre ligne de commande, comme ceci :
tcc -f87 -mX monratio |
Cela indique à Turbo C de générer des appels en ligne vers la puce 8087/80287. Lorsque TLINK est appelé, les fichiers FP87.LIB et MATHx.LIB sont liés. Si vous liez manuellement le code résultant, vous devez spécifier à la fois la bibliothèque mathématique appropriée (en fonction de la taille du modèle) et la bibliothèque FP87, comme ceci :
tlink lib\c0X monratio, monratio, monratio, lib\fp87.lib lib\mathX.lib lib\cX.lib |
où, comme toujours, X est une lettre indiquant la bibliothèque de modèles appropriée.
Si vous n'utilisez pas de virgule flottante...
Si votre programme n'utilise aucune routine à virgule flottante, l'éditeur de liens ne se liera dans aucune des bibliothèques à virgule flottante (EMU.LIB ou FP87.LIB, avec MATHx.LIB) au moment de la liaison, même si vous les avez listées sur la ligne de commande. Vous pouvez optimiser l'étape de lien en omettant ces bibliothèques de la ligne de commande de l'éditeur de liens (si, comme nous l'avons dit, votre programme n'utilise pas de virgule flottante). Supposons que vous souhaitiez compiler et lier le programme suivant (enregistré sous MONRATIO.C) :
Puisque ce programme n'utilise pas de routines à virgule flottante, vous pouvez choisir de le compiler avec l'émulation à virgule flottante activée ou sans virgule flottante du tout. Si vous utilisez TC (la version de l'interface utilisateur) et choisissez de compiler avec l'émulation activée, sélectionnez simplement Compile to OBJ dans le menu Compile. (L'émulation activée est la valeur par défaut.) L'éditeur de liens inclura les bibliothèques à virgule flottante à l'étape de liaison, mais aucune ne sera réellement liée.
Si vous souhaitez accélérer le processus de liaison, vous pouvez spécifier «no floating point.». Allez dans le menu Options, sélectionnez Compiler, sélectionnez Code generation, puis sélectionnez l'élément Floating point. Appuyez plusieurs fois sur Enter à cette commande pour parcourir trois options : None, Emulation et 8087/80287. Vous voulez l'option None. Vous pouvez ensuite appuyer trois fois sur Esc pour revenir à la barre de menu (ou appuyer simplement sur F10). Lorsque vous compilez et liez ce programme avec virgule flottante définie sur None, le Turbo C ne tente pas de se lier dans des routines mathématiques à virgule flottante. Si vous utilisez TCC (le compilateur autonome), vous devez utiliser l'option -f sur votre ligne de commande, comme ceci :
tcc -f- -mX monratio.c |
Il indique à Turbo C que vous n'avez aucune instruction en virgule flottante dans votre programme. Il indique également que vous avez utilisé le modèle de mémoire x, où x est une lettre indiquant le modèle souhaité (t = tiny, s = small, c = compact, m = medium, l = large, h = huge). Puisque MONRATIO.C est un programme autonome, le TCC appellera automatiquement TLINK, établissant des liens dans C0x.OBJ et Cx.LIB, et produisant MONRATIO.EXE. Si vous avez utilisé l'option "compile only" (-c) sur la ligne de commande TCC, vous devez lier manuellement le code résultant. Dans ce cas, vous n'avez pas besoin de (et ne devriez pas) spécifier de bibliothèque mathématique; votre appel de TLINK devrait ressembler à ceci :
tlink lib\c0x monratio, monratio, monratio, lib\cx.lib |
Celui-ci relie C0x.OBJ et RATIO.OBJ, utilise la bibliothèque Cx.LIB et produit les fichiers MONRATIO.EXE et MONRATIO.MAP.
La variable d'environnement 87
Si vous construisez votre programme avec l'émulation 8087 (en d'autres termes, vous sélectionnez Floating point ... Emulation à partir des menus ou vous incluez l'option -f sur la ligne de commande TCC), le module de démarrage C0x.OBJ utilisera la logique de détection automatique 8087 lorsque vous exécutez le programme. Cela signifie que le code de démarrage vérifiera automatiquement si un 8087 est disponible. Si le 8087 est disponible, le programme l'utilisera; s'il n'y est pas, le programme utilisera les routines d'émulation.
Dans certains cas, vous souhaiterez peut-être remplacer ce comportement de détection automatique par défaut. Par exemple, votre propre système d'exécution peut avoir un 8087, mais vous devez vérifier que votre programme fonctionnera comme prévu sur les systèmes sans coprocesseur. Ou votre programme peut avoir besoin de s'exécuter sur un système compatible PC, mais ce système particulier renvoie des informations incorrectes à la logique de détection automatique (en disant qu'un 8087 inexistant est disponible, ou vice versa). Le Turbo C fournit une option pour remplacer la logique de détection automatique par défaut du code de démarrage; cette option est la variable d'environnement 87. Vous définissez la variable d'environnement 87 au prompt DOS avec la commande SET, comme ceci :
SET 87=N |
ou
SET 87=Y |
La définition de la variable d'environnement 87 sur N (pour Non) indique au code de démarrage que vous ne souhaitez pas utiliser le 8087 (même s'il peut être présent dans le système). Inversement, définir la variable d'environnement 87 sur Y (pour Oui) signifie que le coprocesseur est là et que vous souhaitez que le programme l'utilise. Avertissement de programmeur ! Si vous définissez 87=Y alors qu'en fait, il n'y a pas de 8087 disponible sur ce système, votre programme plantera. La variable d'environnement 87 peut remplacer la logique de détection automatique par défaut car, lorsque vous commencez à exécuter votre programme, le code de démarrage vérifie d'abord si la variable 87 a été définie.
- Si la variable 87 a été définie, le code de démarrage ne cherche pas plus loin et votre programme s'exécute dans le mode prescrit.
- Si la variable 87 n'a pas été définie, le code de démarrage passe par sa logique de détection automatique pour voir si une puce 8087 est disponible, et le programme s'exécute en conséquence.
Si la variable d'environnement 87 a été définie (avec une valeur quelconque) mais que vous souhaitez l'annuler, entrez ce qui suit au prompt DOS :
SET 87= |
Cela signifie appuyez sur Enter immédiatement après avoir tapé le signe égal.
Registres et le 8087
Il y a quelques points relatifs aux registres dont vous devez être conscient lorsque vous utilisez la virgule flottante. Premièrement, en mode d'émulation 8087, le bouclage de registre n'est pas pris en charge. Deuxièmement, si vous mélangez la virgule flottante avec l'assemblage en ligne, vous devrez peut-être faire attention lors de l'utilisation de registres. En effet, l'ensemble de registres 8087 est vidé avant que Turbo C n'appelle une fonction. Vous devrez peut-être ouvrir et sauvegarder les registres 8087 avant d'appeler des fonctions utilisant le coprocesseur, sauf si vous êtes sûr qu'il existe suffisamment de registres libres.
Utilisation de matherr avec virgule flottante
Lorsqu'une erreur est détectée dans l'une des routines à virgule flottante pendant l'exécution d'un programme, cette routine appelle automatiquement _matherr avec plusieurs paramètres. La fonction _matherr remplit ensuite une structure d'exception (définie dans math.h) avec ses paramètres et appelle matherr avec un pointeur vers cette structure. La routine matherr est un crochet que vous pouvez utiliser pour écrire votre propre routine de résolution d'erreurs. Par défaut, la fonction matherr ne fait rien d'autre que retourner 0. Cependant, vous pouvez modifier la fonction matherr pour traiter les erreurs de routine en virgule flottante comme vous le souhaitez. Une telle fonction matherr modifié renvoie alors une valeur différente de zéro si l'erreur a été résolue, ou 0 si ce n'est pas le cas.