J'ai remarqu=E9 un truc qui me semble un peu bizarre en manipulant des
unsigned int et des int. Je suis tomb=E9 sur le probl=E8me dans un code C+
+, mais un programme de test en C me donne la m=EAme chose, et j'ai le
m=EAme comportement sur 3 compilateurs diff=E9rents, donc il doit
d=E9finitivement y avoir une logique derri=E8re tout =E7a.
Voil=E0 le code :
#include <stdio.h>
int main(int argc, char** argv) {
unsigned int i;
int a, b, c;
i =3D 100;
printf("%u\n", i);
a =3D -1 * i;
printf("%d\n", a);
/* les parentheses sont justes pour expliciter l'ordre, mais
elles sont inutiles */
b =3D (-1 * i) * 2;
printf("%d\n", b);
c =3D (-1 * i) / 2;
printf("%d\n", c);
return 0;
}
Et le r=E9sultat est :
100
-100
-200
2147483598
Je n'arrive pas =E0 suivre toutes les conversions implicites qui ont
lieu. Au passage, je pr=E9cise que j'ai test=E9 en d=E9finissant des
variables pour mes constantes -1 et 2 (de type int ou unsigned),
histoire de forcer le type, et j'ai toujours le m=EAme comportement.
Pour le premier print (i), rien =E0 dire =E9videmment. Dans le deuxi=E8me
cas, je suppose que i est cast=E9 en int avant de multiplier par -1 ?
Pour le troisi=E8me cas, idem ? Dans le 4=E8me, j'obtiens (2^31 - 100) /
2. Pourquoi ?
Que (unsigned int)(-1) me donne 4 294 967 295 ( =3D 2^32 - 1), OK, je
n'ai pas de probl=E8me avec l'over/underflow. Mais pourquoi multiplier
un unsigned par -1 me donne ce r=E9sultat ?
Et pourquoi j'ai ce r=E9sultat uniquement si je divise apr=E8s (c), et pas
si je multiplie (b) ou que je me contente de stocker le r=E9sultat (a) ?
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Marc Boyer
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des unsigned int et des int.
Le truc dangeureux par nature.
Je suis tombé sur le problème dans un code C+ +, mais un programme de test en C me donne la même chose, et j'ai le même comportement sur 3 compilateurs différents, donc il doit définitivement y avoir une logique derrière tout ça.
Et oui. Disons pour faire simple que "souvent", quand il y a un signé et un non signé dans la même expression, le signé est convertit en non signé (et non l'inverse...).
Voilà le code : #include <stdio.h> int main(int argc, char** argv) { unsigned int i; int a, b, c;
i = 100; printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je n'arrive pas à suivre toutes les conversions implicites qui ont lieu.
Ben, moi j'en sais juste assez pour savoir qu'il faut faire attention. Dans 6.3.1.8/1, il y a le paragraphe qui te concerne: "Otherwise [ie un signé et un non signé] if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type."
Et sans entrer dans les détails int et unsigned int ont le même rank.
Pour le premier print (i), rien à dire évidemment. Dans le deuxième cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
-- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des
unsigned int et des int.
Le truc dangeureux par nature.
Je suis tombé sur le problème dans un code C+
+, mais un programme de test en C me donne la même chose, et j'ai le
même comportement sur 3 compilateurs différents, donc il doit
définitivement y avoir une logique derrière tout ça.
Et oui.
Disons pour faire simple que "souvent", quand il y a un signé et
un non signé dans la même expression, le signé est convertit en
non signé (et non l'inverse...).
Voilà le code :
#include <stdio.h>
int main(int argc, char** argv) {
unsigned int i;
int a, b, c;
i = 100;
printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite,
on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX
puis on reconvertit le tout en int (ce qui doit être une conversion
dépendante de l'encodage "implementation-defined"), et, sur ta
plateforme en complément à 2, ça doit donner -100.
Je n'arrive pas à suivre toutes les conversions implicites qui ont
lieu.
Ben, moi j'en sais juste assez pour savoir qu'il faut faire
attention. Dans 6.3.1.8/1, il y a le paragraphe qui te concerne:
"Otherwise [ie un signé et un non signé] if the operand that has
unsigned integer type has rank greater or equal to the rank of
the type of the other operand, then the operand with
signed integer type is converted to the type of the operand with
unsigned integer type."
Et sans entrer dans les détails int et unsigned int ont le même rank.
Pour le premier print (i), rien à dire évidemment. Dans le deuxième
cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des unsigned int et des int.
Le truc dangeureux par nature.
Je suis tombé sur le problème dans un code C+ +, mais un programme de test en C me donne la même chose, et j'ai le même comportement sur 3 compilateurs différents, donc il doit définitivement y avoir une logique derrière tout ça.
Et oui. Disons pour faire simple que "souvent", quand il y a un signé et un non signé dans la même expression, le signé est convertit en non signé (et non l'inverse...).
Voilà le code : #include <stdio.h> int main(int argc, char** argv) { unsigned int i; int a, b, c;
i = 100; printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je n'arrive pas à suivre toutes les conversions implicites qui ont lieu.
Ben, moi j'en sais juste assez pour savoir qu'il faut faire attention. Dans 6.3.1.8/1, il y a le paragraphe qui te concerne: "Otherwise [ie un signé et un non signé] if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type."
Et sans entrer dans les détails int et unsigned int ont le même rank.
Pour le premier print (i), rien à dire évidemment. Dans le deuxième cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
-- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Rémi Moyen
On Feb 29, 12:55 pm, Marc Boyer wrote:
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des unsigned int et des int.
Le truc dangeureux par nature.
Oui, je sais... Pour tout dire, je n'ai pas l'intention de laisser un truc de ce genre dans mon code, mais comme je suis tombé là-dessus par hasard, j'essaie de comprendre la raison du pourquoi...
Disons pour faire simple que "souvent", quand il y a un signé et un non signé dans la même expression, le signé est convertit en non signé (et non l'inverse...).
OK.
unsigned int i; int a, b, c;
i = 100; printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
Pour le premier print (i), rien à dire évidemment. Dans le deuxièm e cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
En effet, en regardant les choses dans ce sens-là, je comprends ce qui se passe (j'ai fait les calculs à la main avec des char/unsigned char et i et je retombe bien sur le résultat que me donne mon programme en suivant ton raisonnement).
Merci ! -- Rémi Moyen
On Feb 29, 12:55 pm, Marc Boyer <Marc.Bo...@enseeiht.yahoo.fr.invalid>
wrote:
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des
unsigned int et des int.
Le truc dangeureux par nature.
Oui, je sais... Pour tout dire, je n'ai pas l'intention de laisser un
truc de ce genre dans mon code, mais comme je suis tombé là-dessus par
hasard, j'essaie de comprendre la raison du pourquoi...
Disons pour faire simple que "souvent", quand il y a un signé et
un non signé dans la même expression, le signé est convertit en
non signé (et non l'inverse...).
OK.
unsigned int i;
int a, b, c;
i = 100;
printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite,
on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX
puis on reconvertit le tout en int (ce qui doit être une conversion
dépendante de l'encodage "implementation-defined"), et, sur ta
plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux
2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente
des deux autres --, donc les implémentations sont quand même vachement
similaires, mais peu importe, et je comprends que rien n'empêche que
ce ne soit pas le cas sur une 4ème plateforme...).
Pour le premier print (i), rien à dire évidemment. Dans le deuxièm e
cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
En effet, en regardant les choses dans ce sens-là, je comprends ce qui
se passe (j'ai fait les calculs à la main avec des char/unsigned char
et i=10 et je retombe bien sur le résultat que me donne mon programme
en suivant ton raisonnement).
J'ai remarqué un truc qui me semble un peu bizarre en manipulant des unsigned int et des int.
Le truc dangeureux par nature.
Oui, je sais... Pour tout dire, je n'ai pas l'intention de laisser un truc de ce genre dans mon code, mais comme je suis tombé là-dessus par hasard, j'essaie de comprendre la raison du pourquoi...
Disons pour faire simple que "souvent", quand il y a un signé et un non signé dans la même expression, le signé est convertit en non signé (et non l'inverse...).
OK.
unsigned int i; int a, b, c;
i = 100; printf("%un", i);
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
Pour le premier print (i), rien à dire évidemment. Dans le deuxièm e cas, je suppose que i est casté en int avant de multiplier par -1 ?
Perdu, c'est le contraire.
En effet, en regardant les choses dans ce sens-là, je comprends ce qui se passe (j'ai fait les calculs à la main avec des char/unsigned char et i et je retombe bien sur le résultat que me donne mon programme en suivant ton raisonnement).
Merci ! -- Rémi Moyen
Marc Boyer
On 2008-02-29, Rémi Moyen wrote:
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
Ici, c'est surtout du à l'encodage en complément à 2. Bon, ok, pour trouver une machine qui soit pas en complément à deux de nos jours, faut chercher un peu...
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
On 2008-02-29, Rémi Moyen <rmoyen@gmail.com> wrote:
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite,
on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX
puis on reconvertit le tout en int (ce qui doit être une conversion
dépendante de l'encodage "implementation-defined"), et, sur ta
plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux
2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente
des deux autres --, donc les implémentations sont quand même vachement
similaires, mais peu importe, et je comprends que rien n'empêche que
ce ne soit pas le cas sur une 4ème plateforme...).
Ici, c'est surtout du à l'encodage en complément à 2. Bon, ok,
pour trouver une machine qui soit pas en complément à deux de nos
jours, faut chercher un peu...
Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int (ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
Ici, c'est surtout du à l'encodage en complément à 2. Bon, ok, pour trouver une machine qui soit pas en complément à deux de nos jours, faut chercher un peu...
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Jean-Marc Bourguet
"Rémi Moyen" writes:
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int Non,
((UINT_MAX-1)*100) % (UINT_MAX+1) ou ((UINT_MAX-1)*100) & UINT_MAX
(ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
La boutidude n'a pas d'influence la dessus (elle n'intervient que quand tu interpretes de la memoire comme etant composees d'elements de tailles differentes). Il est vraisemblable que toutes les machines dont tu disposes soient en complement a 2, les autres sont rares.
A+
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
"Rémi Moyen" <rmoyen@gmail.com> writes:
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite,
on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int
Non,
((UINT_MAX-1)*100) % (UINT_MAX+1)
ou
((UINT_MAX-1)*100) & UINT_MAX
(ce qui doit être une conversion dépendante de l'encodage
"implementation-defined"), et, sur ta plateforme en complément à 2, ça
doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux
2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente
des deux autres --, donc les implémentations sont quand même vachement
similaires, mais peu importe, et je comprends que rien n'empêche que
ce ne soit pas le cas sur une 4ème plateforme...).
La boutidude n'a pas d'influence la dessus (elle n'intervient que quand tu
interpretes de la memoire comme etant composees d'elements de tailles
differentes). Il est vraisemblable que toutes les machines dont tu
disposes soient en complement a 2, les autres sont rares.
A+
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int Non,
((UINT_MAX-1)*100) % (UINT_MAX+1) ou ((UINT_MAX-1)*100) & UINT_MAX
(ce qui doit être une conversion dépendante de l'encodage "implementation-defined"), et, sur ta plateforme en complément à 2, ça doit donner -100.
Je vois, en effet (ceci dit, j'ai quand même testé sur un PC Linux 2.4, un PC Linux 2.6 et une Sun -- dont l'endianness est différente des deux autres --, donc les implémentations sont quand même vachement similaires, mais peu importe, et je comprends que rien n'empêche que ce ne soit pas le cas sur une 4ème plateforme...).
La boutidude n'a pas d'influence la dessus (elle n'intervient que quand tu interpretes de la memoire comme etant composees d'elements de tailles differentes). Il est vraisemblable que toutes les machines dont tu disposes soient en complement a 2, les autres sont rares.
A+
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
Marc Boyer
On 2008-02-29, Jean-Marc Bourguet wrote:
"Rémi Moyen" writes:
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int Non,
((UINT_MAX-1)*100) % (UINT_MAX+1)
Oui, bien sûr, pardon. Ceci dit, on est vendredi ;-)
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
On 2008-02-29, Jean-Marc Bourguet <jm@bourguet.org> wrote:
"Rémi Moyen" <rmoyen@gmail.com> writes:
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite,
on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int
Non,
((UINT_MAX-1)*100) % (UINT_MAX+1)
Oui, bien sûr, pardon.
Ceci dit, on est vendredi ;-)
Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1). Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX puis on reconvertit le tout en int Non,
((UINT_MAX-1)*100) % (UINT_MAX+1)
Oui, bien sûr, pardon. Ceci dit, on est vendredi ;-)
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Antoine Leca
En news:, Marc Boyer va escriure:
unsigned int i; int a, b, c;
i = 100; a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int est convertit en unsigned, donc, il vaut (UINT_MAX-1).
UINT_MAX
Ensuite, on multiplie cet entier par 100, et on obtient ((UINT_MAX-1)*100) % UINT_MAX ( UINT_MAX *100) %(UINT_MAX+1)
Antoine
En news:slrnfsg05n.377.Marc.Boyer@ubu.enseeiht.fr,
Marc Boyer va escriure:
unsigned int i;
int a, b, c;
i = 100;
a = -1 * i;
Si on décompose ce code, on a un int et un unsigned. L'int
est convertit en unsigned, donc, il vaut (UINT_MAX-1).
UINT_MAX
Ensuite, on multiplie cet entier par 100, et on obtient
((UINT_MAX-1)*100) % UINT_MAX
( UINT_MAX *100) %(UINT_MAX+1)