en ce qui concerne l’opérateur de décalage à gauche et à droite

void times(unsigned short int time) { hours=time>>11; minutes=((time<>10); } 

Prendre le time saisie pour être 24446

Les valeurs de sortie sont

heures = 11

minutes = 763

Les valeurs attendues sont

heures = 11

minutes = 59

Quel traitement interne est en cours dans ce code?

La binary de 24446 est 0101111101111110

Time>>11 donne 01011 ce qui signifie 11 .

((Time<>10) donne 111011 ce qui signifie 59 .

Mais quoi d’autre se passe ici?

Quoi d’autre se passe ici?

Si le time unsigned short , il y a une différence importante entre

 minutes=((time<<5)>>10); 

et

 unsigned short temp = time << 5; minutes = temp >> 10; 

Dans les deux expressions, le time << 5 est calculé comme un entier en raison des règles de promotion d'entier. [Notes 1 et 2].

Dans la première expression, ce résultat int est ensuite décalé à droite de 10. Dans la seconde expression, l'affectation à unsigned short temp réduit le résultat à un short , qui est ensuite décalé à droite de 10.

Ainsi, dans la deuxième expression, les bits de poids fort sont supprimés (par la unsigned short ), tandis que dans la première expression, ils ne seront pas supprimés si int est plus large que short .

Il y a une autre mise en garde importante avec la première expression. Étant donné que les promotions d’entier peuvent transformer un unsigned short en un entier, la valeur intermédiaire peut être signée, auquel cas un débordement serait possible si le décalage à gauche était suffisamment grand. (Dans ce cas, ce n'est pas le cas.) Le décalage de droite peut ensuite être appliqué à un nombre négatif, le résultat est "défini par la mise en oeuvre"; de nombreuses implémentations définissent le comportement de décalage à droite d'un nombre négatif comme une extension du signe. Cela peut aussi conduire à des sursockets.


Remarques:

  1. En supposant que int est plus large que short . Si unsigned int et unsigned short ont la même largeur, aucune conversion ne se produit et vous ne verrez pas la différence que vous décrivez. Les "promotions entières" sont décrites au § 6.3.1.1 / 2 de la norme C (à l'aide du projet de loi C11):

    Si un int peut représenter toutes les valeurs du type d'origine (comme le limite la largeur, pour un champ de bits), la valeur est convertie en un int ; sinon, il est converti en un unsigned int . Celles-ci sont appelées promotions entières. Tous les autres types ne sont pas modifiés par les promotions entières.

    Les règles de promotion de nombre entier empêchent en effet d'effectuer un calcul arithmétique directement avec un type inférieur à int , bien que les compilateurs puissent utiliser la règle de scénario pour utiliser des codes d'opération de sous-mots. Dans ce cas, ils doivent produire le même résultat que celui qui aurait été obtenu avec les valeurs promues; c'est facile pour l'addition et la multiplication non signées, mais plus compliqué pour le décalage.

  2. Les opérateurs de décalage de bits sont une exception à la sémantique des opérations arithmétiques. Pour la plupart des opérations arithmétiques, la norme C exige que "les conversions arithmétiques habituelles" soient appliquées avant d'effectuer l'opération. Les conversions arithmétiques habituelles, entre autres choses, garantissent que les deux opérandes ont le même type, qui sera également le type du résultat. Pour les décalages de bits, la norme exige seulement que des promotions d'entier soient effectuées sur les deux opérandes et que le résultat ait le type de l'opérande gauche. C'est parce que les opérateurs de quart ne sont pas symésortingques. Pour presque toutes les architectures, il n'y a pas d'opérande droit valide pour un décalage qui ne tiendra pas dans un caractère non signé, et il n'est évidemment pas nécessaire que les types ou même la signature des opérandes gauche et droit soient identiques.

    En tout état de cause, comme pour tous les opérateurs arithmétiques, les promotions d'entier (au moins) vont être effectuées. Vous ne verrez donc pas de résultats intermédiaires plus étroits qu'un int .

Ce morceau de code semble penser que int est de 16 bits et que le temps de décalage à gauche efface les 5 premiers bits.

Puisque vous travaillez probablement en 32/64 bits, cela ne se produit pas si la valeur dans le time est une valeur de 16 bits:

time >> 5 == (time << 5) >> 10

Essaye ça:

 minutes = (time >> 5) & 0x3F; 

ou

 minutes = (time & 0x07FF) >> 5; 

ou

Déclarez le time tant que unsigned short et transformez-le en un unsigned short après chaque opération de décalage, car le calcul est 32/64 bits.

24446 en binary est: 0101 1111 0111 1110

  • Bits 0-4 – inconnu
  • Bits 5-10 minutes
  • Bits 11-16 heures

Il semble que la taille de ‘int’ pour la plate-forme que vous travaillez sur 32 bits. En ce qui concerne le traitement, supposons que, la première déclaration divise le “temps” par “11”. La deuxième déclaration multiplie le “temps” par 5, puis divise le tout par 10. La réponse à votre question se termine ici.

Si vous ajoutez ce que la valeur de temps contient réellement (nombre de secondes / millisecondes / heures ou quelque chose d’autre), vous obtiendrez peut-être plus d’aide.

Edit: Comme @egur l’a souligné, vous pourriez porter votre code de la plate-forme 16 bits à la plate-forme 32/64 bits. Un style de code C largement accepté pour rendre le code portable est le suivant:

créer le fichier Typedef.h et l’inclure dans tous les autres fichiers C,

  //Typedef.h typedef unsigned int U16 typedef signed int S16 typedef unsigned short U8 typedef signed short S8 : : //END 

Utilisez U16, U8, etc. en déclarant des variables.

Maintenant, lorsque vous passez à un processeur plus gros, dites 32 bits, changez votre Typedef.h en

  //Typedef.h typedef unsigned int U32 typedef signed int S32 typedef unsigned short U16 typedef signed short S16 

Pas besoin de changer quoi que ce soit dans le code de repos.

edit2:

après avoir vu votre modification:

  ((Time<<5)>>10) gives 111011 which means 59. 

Pour les processeurs 32 bits

  ((Time<<5)>>10) gives 0000 0010 1111 1011 which means 763.