Types et opérations en langage C

Le problème exposé dans ce sujet a été résolu.

Bonjour, j’ai une question par rapport aux types et aux opérations en langage C :

Lorsque je demande à l’ordinateur d’exécuter printf("%u", 7 - 5U), comment fait-il pour calculer $7 - 5$?

Ce que je veux dire, c’est qu’il calculera certainement $7 + (-5)$ donc il convertira unsigned int en signed int.

Je me suis fait cette réflexion car je constate que printf("%d", 7 - 5U) renvoie exactement le même résultat.

J’avais donc pensé à un truc du genre int - unsigned int = int + signed int = int mais je n’en suis pas certain.

D’autant plus que ça doit cacher un tas de choses compliquées…

Merci pour votre attention.

+1 -0

Hello,

Ici le type de la variable n’a aucun impact sur sa valeur réelle. En informatique tout est nombre, représenté par des 0 et des 1.

Le calcul sera exactement le même ; après, ce sera la façon dont tu affiches/interprètes la donnée qui fera foi sur le résultat que tu observeras en tant qu’utilisateur.

Sur 8 bits et en mode unsigned, par exemple, 5 - 7 donnera 254. Cette valeur est la même que -2 lorsque tu intérprètes le nombre en mode signed.

Par exemple, les deux instructions suivantes :

1
2
unsigned char number1 = 254;
signed char number2 = -2;

Donne en langage machine :

1
2
mov    BYTE PTR [rbp-0x2],0xfe
mov    BYTE PTR [rbp-0x1],0xfe

Il s’agit des mêmes nombres en mémoire.

… Au final, pour répondre à ta question :

J’avais donc pensé à un truc du genre int - unsigned int = int + signed int = int mais je n’en suis pas certain.

Moi non plus je n’en suis pas certain, mais je pense que tu as raison. Un peu comme pour le fait d’avoir un flottant dans au moins une des deux opérandes d’une division pour obtenir un résultat flottant.

Quelqu’un d’autre t’éclairera dessus à ma place, je pense. :)

A bientôt

Edit : 5 - 7, pas 7 - 5… Edit 2 : 8 bits, pas 128…

+0 -0

Salut,

Je ne pense pas qu’une conversion s’effectue ici, puisque l’instruction de soustraction existe en ASM, 7-5 ne devient donc pas 7+(-5), soit ADD 7,-5;, mais directement SUB 7,5;

la différence entre un int et un unsigned int ne se fait qu’une fois le MSB à 1 car il s’agit du bit de signe dans le cas d’un entier signé tandis que c’est juste le MSB pour les non signés. 7 et 5 ont donc la même représentation que l’entier soit signé ou non, soit 0…0111 et 0…0101.
Quand au format affiché par le printf, %u et %d sont une indication donnée à la fonction pour afficher de manière formatée la donnée que tu lui donne, mais il n’y a pas de vérification de type, tu pourrais aussi bien afficher le résultat de 7-5U sous forme de caractère avec %c.
%d et %u t’ont donc affiché le même résultat car peu importe que le retour du calcul soit un entier signé ou non signé, le résultat est 0…0010 soit 2 dans chacun des formats.

+0 -0

Ici le type de la variable n’a aucun impact sur sa valeur réelle.

Non. Certains types offrent des garanties en cas d’overflow alors que d’autres amènent à un UB. Donc il y’a clairement une influence.

Sinon, pour le PO, ce sont les règles de conversion implicites: cf ici

Davidbrcz

Quand tu fais des opérations sur ces types, oui, tu évites des mauvaises surprises. Ce que j’ai voulu dire, c’est que, indépendamment du type, selon la taille de la donnée, 254 équivaut à -2. Ce sont les mêmes nombres en mémoire.

Salut,

Sur 128 bits et en mode unsigned, par exemple, 5 - 7 donnera 254. Cette valeur est la même que -2 lorsque tu intérprètes le nombre en mode signed.

Ge0

Tu voulais dire sur 8 bits je suppose ?

[…] tu pourrais aussi bien afficher le résultat de 7-5U sous forme de caractère avec %c.

leroivi

Cette pratique est à déconseiller étant donné que printf() emploie un nombre variable d’argument. Cela fonctionnera par exemple sur une machine petit-boutiste, mais pas sur une machine avec un boutisme différent.

Ce que je veux dire, c’est qu’il calculera certainement $7 + (-5)$ donc il convertira unsigned int en signed int.

Ozmox

Les conversions implicites sont expliquées dans cette section du cours sur le C. Dans ton exemple, l’expression entière 7 sera convertie en unsigned int (la seconde opérande étant de type unsigned int et le type signed int ne pouvant représenter toutes ses valeurs). Le résultat de l’opération sera donc de type unsigned int.

Je me suis fait cette réflexion car je constate que printf("%d", 7 - 5U) renvoie exactement le même résultat.

Ozmox

Comme l’on dit mes VDD, cela est lié à la représentation des entiers. Je t’invite à lire cette section du cours sur le C si tu souhaites en savoir plus (attention : c’est une partie avancée du cours).

J’avais donc pensé à un truc du genre int - unsigned int = int + signed int = int mais je n’en suis pas certain.

Ozmox

Nope, comme je l’ai dit : int - unsigned int = unsigned int (sauf si le type signed int peut représenter toutes les valeurs du type unsigned int, ce qui n’arrive jamais, donc osef :-° ).

+0 -0

Comme l’on dit mes VDD, cela est lié à la représentation des entiers. Je t’invite à lire cette section du cours sur le C si tu souhaites en savoir plus (attention : c’est une partie avancée du cours).

Ok donc par rapport à ce point, j’attendrai ce chapitre.

Nope, comme je l’ai dit : int - unsigned int = unsigned int

Ok, j’imagine que ça rejoint ce qu’écrit leroivi à propos de SUB 7, 5?

J’ai lu un autre truc, comme quoi on pouvait effectuer les conversions de la sorte :

int –> unsigned int –> long –> unsigned long –> float –> double –> long double.

Par exemple on peut faire float –> double ou float –> long double mais pas float –> long.

Donc si on a par exemple long + unsigned long / double, on peut faire long –> unsigned long puis unsigned long –> double, ce qui nous donne le type du résultat.

Mais bon, peut-être que je me trompe.

+0 -0

Voici le schéma des conversions :

int –> unsigned int –> long –> unsigned long –> float –> double –> long double

On peut aller de gauche à droite, sauter des étapes mais pas aller vers la gauche pour convertir.

Imaginons que l’on ait long + unsigned long/ double.

On coupe le calcul en deux : long + unsigned long = type n°1 et type n°1 / double = type n°2.

Pour la première partie du calcul, on va convertir unsigned long en long ou bien l’inverse? D’après le schéma, c’est l’inverse, donc type n°1 = unsigned long.

Pour la seconde partie du calcul, on va convertir unsigned long en double ou bien l’inverse? D’après le schéma, c’est le premier cas donc type n°2 = double.

Notre résultat est de type double.

EDIT : Nan mais laissez tomber c’est inutile.

+0 -0

Bof, c’est vrai dans les positifs, c’est bien cet ordre là pour augmenter ton nombre maximum, cependant dès que tu as du négatif, tu ne peux plus le représenter avec un unsigned donc dans le schéma la conversion int -> unsigned int ne fait pas vraiment sens.
De même les nombres flottants (float et double) ont des capacités largement supérieurs, mais ils possèdent une certaine précision inhérente à leurs représentations, ainsi tu ne pourras en fait jamais avoir la valeur 3 dans un nombre flottant, alors que la valeur de l’entier serait exact.

+0 -0

Nope, comme je l’ai dit : int - unsigned int = unsigned int (sauf si le type signed int peut représenter toutes les valeurs du type unsigned int, ce qui n’arrive jamais, donc osef :-° ).

Taurre

Et du coup, printf("%u", 5 - 7U) donne ?

elegance

Logiquement, 0xfffffffe soit 4294967294 en non signé sur 32 bits.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte