Convertir int non signé en signé int C

J’essaye de convertir 65529 d’un unsigned int en un int signé. J’ai essayé de faire un casting comme ça:

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

Mais y retourne toujours 65529 alors qu’il devrait retourner -7. Pourquoi donc?

    Il semble que vous vous attendiez à ce que int et unsigned int soient un entier de 16 bits. Ce n’est apparemment pas le cas. Très probablement, il s’agit d’un entier de 32 bits, ce qui est assez grand pour éviter le bouclage auquel vous vous attendez.

    Notez qu’il n’existe pas de méthode totalement compatible C, car la conversion entre signés / non signés pour des valeurs hors limites est définie par l’implémentation. Mais cela fonctionnera toujours 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  

    Je sais que c’est une vieille question, mais c’est une bonne question, alors qu’en est-il?

     unsigned short int x = 65529U; short int y = *(short int*)&x; printf("%d\n", y); 

    @Mysticial l’a eu. 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 de détail. Tout dépend de la façon dont les numéros signés sont stockés en mémoire. Faites une recherche de la notation deux-complément pour plus de détails, mais voici les bases.

    Alors regardons 65529 décimales. Il peut être représenté sous la forme FFF9h en hexadécimal. Nous pouvons aussi représenter cela en binary comme:

    11111111 11111001

    Lorsque nous déclarons short zz = 65529; , le compilateur interprète 65529 comme une valeur signée. Dans la notation à double complément, le bit supérieur indique si une valeur signée est positive ou négative. Dans ce cas, vous pouvez voir que le bit supérieur est un 1 , il est donc traité comme un nombre négatif. C’est pourquoi il affiche -7 .

    Pour un unsigned short , on se fiche de signer car il est unsigned . Ainsi, lorsque nous l’imprimons à l’aide de %d , nous utilisons les 16 bits, ils sont donc interprétés comme 65529 .

    Pour comprendre pourquoi, vous devez savoir que la CPU représente des nombres signés à l’aide du complément à deux (peut-être pas tous, mais plusieurs).

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

    De plus, le type int et unsigned int peuvent être de tailles différentes en fonction de votre CPU. Lorsque vous faites des choses spécifiques comme ceci:

      #include  int8_t ibyte; uint8_t ubyte; int16_t iword; //...... 

    La représentation des valeurs 65529u et -7 est identique pour les ints 16 bits. Seule l’interprétation des bits est différente.

    Pour les plus grandes valeurs et ces valeurs, vous devez signer extension; une façon est avec des opérations logiques

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

    Si la vitesse n’est pas un problème ou si la division est rapide sur votre processeur,

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

    La multiplication décale à gauche 16 bits (là encore, en supposant une extension de 16 à 32), et la division décale à droite en maintenant le signe.

    Vous vous attendez à ce que votre type int ait une largeur de 16 bits, auquel cas vous obtiendriez une valeur négative. Mais très probablement, il a une largeur 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, essayez quelque chose 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);