Question

Je suis en train de convertir 65529 d'un unsigned int à un int signé. J'ai essayé de faire un casting comme celui-ci:

unsigned int x = 65529;
int y = (int) x;

Mais y est encore de retour 65529 quand il doit revenir -7. Pourquoi?

Était-ce utile?

La solution

Il semble que vous attendez int et unsigned int d'être un entier de 16 bits. C'est apparemment pas le cas. Très probablement, il est un entier de 32 bits -. Qui est assez grand pour éviter le wrap-around que vous vous attendez à

Notez qu'il n'y a aucun moyen de le faire entièrement compatible C parce coulée entre signé / unsigned pour les valeurs hors plage est définie par l'implémentation. Mais cela reste du travail dans la plupart des cas:

unsigned int x = 65529;
int y = (short) x;      //  If short is a 16-bit integer.

ou bien:

unsigned int x = 65529;
int y = (int16_t) x;    //  This is defined in <stdint.h>

Autres conseils

Je sais qu'il est une vieille question, mais il est bon, alors que diriez-vous?

unsigned short int x = 65529U;
short int y = *(short int*)&x;

printf("%d\n", y);

@Mysticial a obtenu. Un court est généralement 16 bits et illustrera la réponse:

int main()  
{
    unsigned int x = 65529;
    int y = (int) x;
    printf("%d\n", y);

    unsigned short z = 65529;
    short zz = (short)z;
    printf("%d\n", zz);
}

65529
-7
Press any key to continue . . .


Un peu plus en détail. Il est tout au sujet de la façon dont les numéros sont signés stockés dans la mémoire. Faites une recherche de notation complément à deux pour plus de détails, mais voici les bases.

Alors regardons 65529 décimal. Il peut être représenté comme FFF9h en hexadécimal. On peut également représenter qu'en binaire:

11111111 11111001

Quand nous déclarons short zz = 65529;, les compilateur interprète 65529 en tant que valeur signée. Dans la notation de complément à deux, le haut bit indique si une valeur est signée positive ou négative. Dans ce cas, vous pouvez voir le bit de haut est un 1, il est traité comme un numéro de négatif. Voilà pourquoi il imprime -7.

Pour un unsigned short, nous ne se soucient pas de signe depuis sa unsigned. Ainsi, lorsque nous l'imprimer à l'aide %d, nous utilisons tous les 16 bits, il est donc interprété comme 65529.

Pour comprendre pourquoi, vous devez savoir que la CPU représente des nombres signés en utilisant le complément à deux (peut-être pas tous, mais beaucoup).

    byte n = 1; //0000 0001 =  1
    n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1

Et aussi, que le type int et unsigned int peuvent être de différentes tailles en fonction de votre CPU. Quand vous faites des trucs spécifiques comme ceci:

   #include <stdint.h>
   int8_t ibyte;
   uint8_t ubyte;
   int16_t iword;
   //......

La représentation des valeurs 65529u et -7 sont identiques pour ints 16 bits. Seule l'interprétation des bits est différent.

Pour ints plus grandes et ces valeurs, vous devez vous étendre; une voie est avec des opérations logiques

int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767

Si la vitesse est pas un problème, ou diviser est rapide sur votre processeur,

int y = ((int ) (x * 65536u)) / 65536;

Les décalages de multiplication à gauche de 16 bits (à nouveau, en supposant que l'extension 16 à 32) et les décalages de diviser le maintien de droite du signe.

Vous attendez que votre type de int est de 16 bits de large, dans ce cas, vous auriez en effet obtenir une valeur négative. Mais le plus probable il est large de 32 bits, donc un int signé peut représenter 65529 très bien. Vous pouvez le vérifier en imprimant sizeof(int).

Pour répondre à la question posée dans le commentaire ci-dessus - quelque chose essayer comme ceci:

unsigned short int x = 65529U;
short int y = (short int)x;

printf("%d\n", y);

ou

unsigned short int x = 65529U;
short int y = 0;

memcpy(&y, &x, sizeof(short int);
printf("%d\n", y);

Depuis la conversion des valeurs non signées utilisent pour représenter des nombres positifs de conversion peut être effectuée en réglant le bit le plus significatif à 0. Par conséquent, un programme ne sera pas interpréter cela comme une valeur de complément Two`s. Une mise en garde est que cela de perdre des informations pour les numéros que près de max du type non signé.

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top