2010-09-23 6 views
1
#include "stdio.h" 

int main() 
{ 
    int x = -13701; 
    unsigned int y = 3; 
    signed short z = x/y; 

    printf("z = %d\n", z); 

    return 0; 
} 

Je m'attendrais à ce que la réponse soit -4567. Je reçois "z = 17278". Pourquoi une promotion de ces nombres aboutit à 17278? J'ai exécuté ceci en Code Pad.Quelles sont les conversions de type?

Répondre

10

Les conversions de type sont cachés:

signed short z = (signed short) (((unsigned int) x)/y); 

Lorsque vous mélangez types signés et non signés ceux non signés gagner. x est convertie en unsigned int, divisé par 3, puis ce résultat est converti à (signé) short. Avec des entiers 32 bits:

(unsigned) -13701   == (unsigned) 0xFFFFCA7B // Bit pattern 
(unsigned) 0xFFFFCA7B  == (unsigned) 4294953595 // Re-interpret as unsigned 
(unsigned) 4294953595/3 == (unsigned) 1431651198 // Divide by 3 
(unsigned) 1431651198  == (unsigned) 0x5555437E // Bit pattern of that result 
(short) 0x5555437E  == (short) 0x437E  // Strip high 16 bits 
(short) 0x437E   == (short) 17278   // Re-interpret as short 

Par ailleurs, le mot-clé signed est inutile. signed short est un moyen plus long de dire short. Le seul type qui nécessite explicitement signed est char. char peut être signé ou non signé selon la plate-forme; tous les autres types sont toujours signés par défaut.

+2

Il est peut-être intéressant de noter que dans le cas général, la conversion * non signé * n'est pas basée sur une réinterprétation. En fait, la conversion et la ré-interprétation sont des choses très, très, très différentes, et ce que nous avons dans ce cas est en fait une * conversion *, pas une réinterprétation. – AnT

+0

++, bonne réponse –

4

Réponse courte: la division favorise d'abord x à unsigned. Seulement alors le résultat est renvoyé à signed short.

Réponse longue: lire this SO thread.

3

Les problèmes vient du unsigned int y. En effet, x/y devient non signé. Il fonctionne avec:

#include "stdio.h" 

int main() 
{ 
    int x = -13701; 
    signed int y = 3; 
    signed short z = x/y; 

    printf("z = %d\n", z); 

    return 0; 
} 
1

Chaque fois que vous mélangez de grandes valeurs signées et non signées dans des opérations arithmétiques additives et multiplicatives, le type non signé "wins" et l'évaluation est effectuée dans le domaine du type non signé. Si votre valeur signée originale était négative, elle sera d'abord convertie en valeur non signée positive conformément aux règles de conversion signées-non signées. Dans votre cas -13701 deviendra UINT_MAX + 1 - 13701 et le résultat sera utilisé comme dividende.

Notez que le résultat de la conversion signed-to-unsigned sur une plate-forme 32 bits int aboutira à la valeur non signée 4294953595. Après la division par 3 vous obtiendrez 1431651198. Cette valeur est trop grande pour être forcée dans un objet short sur une plate-forme avec le type short 16 bits. Une tentative pour ce faire entraîne un comportement défini par l'implémentation. Donc, si les propriétés de votre plate-forme sont les mêmes que dans mes hypothèses, alors votre code produit un comportement défini par l'implémentation. D'un point de vue formel, la valeur 17278 "sans signification" que vous obtenez n'est rien de plus qu'une manifestation spécifique de ce comportement défini par l'implémentation. Il est possible que si vous avez compilé votre code avec la vérification de débordement activée (si votre compilateur les prend en charge), il piègerait sur l'affectation.

+0

En fait, ce comportement n'est pas indéfini: la norme dit que le résultat est défini par l'implémentation ou qu'un signal défini par l'implémentation est déclenché (la conversion vers un type signé plus étroit est distincte du débordement). – caf

+0

@caf: Vous avez raison. Merci pour la correction. Hmm ... Je me souviens avoir fait cette remarque correctrice moi-même plusieurs fois, mais dans ce cas, j'ai d'une manière ou d'une autre oublié tout :) – AnT

Questions connexes