2 votes

Qu'est-ce qui effectue la conversion dans le code C, compilé avec gcc sur Linux?

Question courte: si je fais ceci :

double x = 3.152;
int y = (int) x;

y devrait stocker la valeur 3. Est-ce que gcc appelle une fonction qui effectue ce cast ? Si oui, où est-elle située et comment puis-je écrire la mienne et indiquer à gcc de l'utiliser ?

Question longue avec des informations de base :

Je suis en train d'écrire un OS, et je réécris la bibliothèque standard en C, dans le cadre d'un projet d'apprentissage personnel. En conséquence, j'ai désactivé beaucoup de choses dans ma compilation de code C. Plus précisément, j'utilise les drapeaux suivants :

-nostartfiles -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nodefaultlibs

J'ai eu beaucoup de succès en travaillant avec des entiers, mais je passe maintenant à des doubles, et j'ai essayé de caster un double en un entier. Ce qui se passe, c'est qu'il ne se passe rien du tout. Je soupçonne donc que quelque part dans toutes ces choses que j'ai désactivées se trouve le code qui effectue réellement le cast. Je suis prêt à le réécrire, car c'est un apprentissage fascinant pour moi, mais je ne sais pas ce que je suis censé réécrire.

2voto

JeremyP Points 46808

J'ai compilé votre code avec l'option -S pour obtenir de l'assembleur et j'ai regardé cela. Je dois dire que j'utilise Clang sur OS X mais je pense que gcc fera la même chose. Ce qu'il a fait était d'utiliser une instruction cvttsd2si qui convertit un nombre flottant en double précision en un entier signé en une seule instruction en langage machine.

C'est spécifique à l'architecture x86_64. S'il n'y a pas d'instruction équivalente dans l'architecture cible, le compilateur insérera un appel à une fonction intégrée qui effectue la conversion.

Si votre programme se compile et se lie sans problèmes (sans aucune bibliothèque ou fonction intégrée), alors votre code utilise probablement une seule instruction, sinon je m'attendrais à une erreur de liaison, mais vous devez vous assurer que le compilateur n'optimise pas votre code de sorte qu'il n'ait pas besoin de faire la conversion. Par exemple

 int main()
 {
     double y = 3.14159;
     int x = (int) y;
     return 0;
 }

pourrait facilement être optimisé pour juste exécuter la partie return 0.

2voto

dwelch Points 27195

Cela fait partie du langage tout comme l'addition de deux nombres, le compilateur doit savoir comment faire et appliquer cela à la cible (afin de prendre en charge pleinement ce langage). Il peut ou non appeler une fonction en fonction de ce que la cible prend en charge, s'il n'y a pas de matériel à virgule flottante dans la cible, alors il doit appeler une bibliothèque logicielle pour effectuer la conversion double en entier. Il y a parfois des raisons pour lesquelles un point flottant dur ne peut pas faire certaines choses et/ou des raisons d'implémentation et de conception de compilateur pour lesquelles ils peuvent toujours choisir d'appeler une fonction pour effectuer la conversion double en entier même s'il existe un FPU dur.

Ces bibliothèques, si elles sont utilisées, sont parfois appelées bibliothèques de compilateur, dans GCC dans la catégorie gcclib ou bibliothèques GCC. Généralement pas quelque chose que vous voyez (en arrière-plan)... Ce n'est pas limité aux nombres à virgule flottante, vous verrez des appels de bibliothèque similaires pour l'addition, la soustraction, la multiplication, la division, ainsi que pour les opérations à virgule flottante que le langage C prend en charge et que la cible ne prend pas nécessairement en charge directement. (ajout de deux entiers de 64 bits sur un processeur de 32 bits, division entière sur un processeur sans division matérielle, multiplication signée sur un processeur qui prend en charge uniquement la multiplication non signée, etc).

Il n'y a pas de réponse unique à cette question, cela varie en fonction du compilateur, de la version du compilateur et de la cible.

ÉDITER

En ce qui concerne l'écriture d'un système d'exploitation, cela est enfoui dans le compilateur vous ne devriez pas y être exposé au niveau du système d'exploitation. Le compilateur doit faire son travail de production de code fonctionnel pour la cible (dont votre OS fait partie de la cible, mais...) qui, à la fin de la journée, est beaucoup de code machine, dont une partie est du code machine direct qui effectue la conversion double en int ou une bibliothèque GCC qui est liée et qui a du code machine qui effectue cette opération. Ainsi, votre système d'exploitation ne devrait pas se soucier de cela. Cependant, il y a des moments où l'implémentation logicielle de quelque chose a, par exemple, une division par zéro et veut prendre une mesure à ce sujet qui pourrait être un appel de bibliothèque C qui pourrait ensuite devenir un appel système. Une implémentation matérielle de division directe flottante ou entière, pourrait avoir une interruption que le système d'exploitation pourrait devoir prendre en charge dans cette situation. Il y a donc une connexion possible ici. Le flottant IEEE-754 a, ou du moins la dernière fois que je l'ai lu il y a un moment, des accroches logicielles/système d'exploitation, ici encore une division par zéro qui est piégée par rapport à une division par zéro qui ne l'est pas peut donner des résultats différents. Pour le cas d'une opération de flottant à entier, il y a la situation d'un NaN converti en entier et je ne connais pas la réponse spécifique à cet égard pour une capture vs pas de capture, mais si votre compilateur génère des fonctions à virgule flottante logicielles pour cela, il peut entraîner l'appel d'autres fonctions qu'il suppose être prises en charge par d'autres bibliothèques GCC et/ou les bibliothèques standard C, ce qui pourrait alors se connecter à quelque chose dans votre système d'exploitation.

1voto

unwind Points 181987

Non, il ne (doit pas) appeler une fonction. Il "sait" simplement (par le fait d'être un compilateur pour un processeur cible particulier) quelle(s) instruction(s) émettre pour effectuer la conversion.

Il pourrait bien sûr choisir d'implémenter cela comme un appel à une sous-routine, si c'est beaucoup de travail, mais sur les processeurs x86 typiques, il s'agit d'une seule instruction donc il émet simplement cela.

Vous devriez inspecter le code que vous avez reçu, la cause la plus probable (pour un code comme celui dans la question, avec une expression constante simple étant convertie) est qu'aucune conversion n'a été effectuée au moment de l'exécution.

1voto

Malcolm McLean Points 5437

Oui, cela appellera probablement une fonction ou du code en ligne.

L'exigence de convertir un type à virgule flottante en un entier est si commune qu'il y a probablement une instruction spéciale en langage machine pour cela. Vous ne pouvez pas y accéder depuis C. Ce que vous pouvez faire, c'est regarder le motif binaire du nombre à virgule flottante, extraire l'exposant, le signe et la mantisse, puis faire la conversion en décalant la mantisse du bon montant, vous devez également ajouter un 1 en tête.

Sur les machines qui n'ont pas un FPU dédié, c'est ainsi que fonctionne la conversion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X