IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Problème de compréhension sur opérateur binaire pour reconstituer un entier.


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 428
    Points : 170
    Points
    170
    Par défaut Problème de compréhension sur opérateur binaire pour reconstituer un entier.
    Bonjour, mon code marche mais je n'arrive pas à comprendre le principe de fonctionnement de
    cette ligne de code : z = d<<24 | c<<16 | b<<8 | a;
    je suis en LITTLE-ENDIAN donc int n=16 777 643 (j'ai pris un grand nombre pour l'exemple)
    s'écrit en bit comme ça :

    1010 1011 0000 0001 0000 0000 000 0001

    Après avoir ranger chaque octet dans un char j'obtiens ceci :
    a=1010 1011
    b=0000 0001
    c=0000 0000
    d=0000 0001

    Je vous explique comment j'ai compris cette ligne : z = d<<24 | c<<16 | b<<8 | a;
    Je suppose ici que le compilateur commence par lire les instructions à gauche donc on décale d
    de 24 bits vers la gauche le problème c'est que je trouve cette instruction illogique car pour moi, un
    char fait 1 octet donc 8 bits si je décale de 24 bits vers la gauche logiquement je perds mes bits
    puisque 1 char fait 8 bits si je décale de 24 bits donc logiquement d vaudra zéro et le 1 sera
    perdu ; idem pour c et b (Si je prends b qui vaut 000 0001 aussi si je le décale de 8 bits le 1 sort du chant de bits du char b).

    Ensuite on nous dit de comparer d décalé de 24 bits à c décalé de 16 bit si on compare 2 char
    avec l'opérateur OU logiquement je devrait avoir ça :

    d = 0000 0001 si on décale : d<<24 donne : 0000 0000 on sort du char d nos bits son perdu
    c = 0000 0000 si on décale : c<<16 donne : 0000 0000 on sort du char c nos bits son perdu

    On applique l'opérateur OU : d<<24 | c<<16 donne : 0000 0000 je met pas la suite et au final on met le résultat final dans z ; voilà comment j'ai compris la chose, pourtant ce n'est pas comme ça que cette ligne fonctionne et pourtant le résultat renvoyer dans z correspond à ma valeur n.

    On devrait plutôt faire comme ceci :

    -------------d
    int z=d : 0000 0001 0000 0000 0000 0000 0000 0000 (on met d dans z)

    ------------------------d
    z=z<<8 : 0000 0000 0000 0001 0000 0000 0000 0000 (on décale de 8 bits vers la gauche)
    c------: 0000 0000 (valeur de c)

    ------------c---------d
    z=z|c : 0000 0000 0000 0001 0000 0000 0000 0000 (Résultat du OU Binaire)

    ------------------------c----------d
    z=z<<8 : 0000 0000 0000 0000 0000 0001 0000 0000 (on décale de 8 bits vers la gauche)
    b-------: 0000 0001 (valeur de b)

    ------------b----------c---------d
    z=z|b : 0000 0001 0000 0000 0000 0001 0000 0000 (Résultat du OU Binaire)

    ------------------------b----------c---------d
    z=z<<8 : 0000 0000 0000 0001 0000 0000 0000 0001 (on décale de 8 bits vers la gauche)
    a-------: 1010 1011 (valeur de a)

    ------------a----------b---------c---------d
    z=z|a : 1010 1011 0000 0001 0000 0000 0000 0001 (Résultat du OU Binaire)
    En résumé :

    z=d;
    z=z<<8;
    z=z|c;
    z=z<<8;
    z=z|b;
    z=z<<8;
    z=z|a;

    Ce qui est ci-dessus est pour moi logique alors que cette ligne là : z = d<<24 | c<<16 | b<<8 | a; ne
    l'est pas du tout puisque l'on décale des char et on les compare ensembles alors que l'on devrait
    mettre les char dans l'entier z au fur et à mesure qu'on les décales on met le premier char d dans
    z, z qu'on décale ensuite on compare z avec le 2eme char on décale etc...

    Si quelqu'un pouvait m'expliquer cette ligne de code z = d<<24 | c<<16 | b<<8 | a;.
    Merci par avance.

    Je vous met le code en entier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char **argv)
    {
        int n=427;
        int z=0;
        unsigned char a, b, c, d;
     
        a=n&255;
        b=n>>8&255;
        c=n>>16&255;
        d=n>>24;
     
        printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
     
    /*z=d;
    z=z<<8; 
    z=z|c;
    z=z<<8;
    z=z|b;
    z=z<<8;
    z=z|a;*/
     
    z = d<<24 | c<<16 | b<<8 | a;
     
       printf("z=%d", z);
       return EXIT_SUCCESS;
    }

  2. #2
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2012
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2012
    Messages : 257
    Points : 321
    Points
    321
    Par défaut
    Bonjour,

    Avec les opérateurs de décalage, il me semble qu'il y a des conversions implicites donc (d<<24) ne reste pas un char.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 360
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 360
    Points : 23 600
    Points
    23 600
    Par défaut
    Bonsoir,

    En effet, avec les opérateurs C (et pas seulement les opérateurs de décalage), lorsque l'on utilise un opérateur à deux opérandes, le résultat n'est pas converti vers le type du premier rencontré (celui de gauche, donc) mais promu vers le type le plus « fort ». C'est ainsi, par exemple, que :


    … va renvoyer « 2 », car « 5 » et « 2 » sont considérés par défaut comme des entiers. Le résultat sera également un entier et sa partie fractionnaire sera tronquée. L'entier en question sera éventuellement converti vers un float ou un double par la suite si le compilateur est suffisamment intelligent pour reconnaître le format de printf (ce qui est pratiquement toujours le cas aujourd'hui), mais le mal sera fait : l'info aura déjà été perdue et reconvertir le tout vers un format flottant ne nous la rendra pas. En revanche :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
        printf("%f\n",5/2.0);

    … va bien renvoyer « 2.5 » parce « 2.0 » est doté d'une décimale et que la grammaire du parser du compilateur l'interprétera directement comme un flottant (même si cette décimale est nulle). Le résultat sera donc exprimé en tant que flottant lui aussi et tout va bien se passer. C'est une astuce de programmeur C que l'on retrouve parfois dans d'autres langages interprétés (par exemple avec gnuplot) et qui évite d'avoir à recourir à des casts explicites.

    En ce qui concerne l'endianess, c'est censé être transparent pour l'utilisateur : le micro-processeur se chargera lui-même de charger un registre depuis la mémoire dans le bon sens et de faire l'opération inverse au moment de l'enregistrer. Tu n'auras donc pas à t'en soucier si tu gères directement une variable. Il faudra y veiller en revanche si tu déréférences des pointeurs ET que ceux-ci ne sont pas du format de la donnée à traiter.

    Enfin, pour être parfaitement rigoureux, tu peux considérer dans un premier temps que 1 char = 1 octet mais ce n'est pas une généralité : il s'agit en fait de l'unité minimum qui soit à la fois adressable par le micro-processeur ET qui puisse représenter la totalité des 95 caractères du jeu de caractères d'exécution de base spécifié par la norme. Ça veut dire que sur un micro-processeur 4 bits, par exemple, il y a de fortes chances pour que le C ne sache incrémenter les adresses que de 2 en 2. Ça fera toujours huit bits, dans ce cas précis, mais certaines architectures exotiques utilisent parfois des mots de 7 bits (devenu rare), de 10 ou de 12 bits (cas des PIC 12Fxxx ou 12Cxxx) et là, le micro-processeur ne pourra pas descendre en dessous. Il faudra utiliser la macro CHAR_BIT pour être fixé.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2011
    Messages
    428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2011
    Messages : 428
    Points : 170
    Points
    170
    Par défaut
    Merci pour vos réponses.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 02/06/2009, 16h03
  2. Réponses: 4
    Dernier message: 18/02/2009, 13h53
  3. Problème de flitre sur une date pour la création d'un recordset
    Par psykodumarteau dans le forum VBA Access
    Réponses: 2
    Dernier message: 03/09/2008, 09h11
  4. Problème de compréhension sur variable %
    Par soso78 dans le forum VB.NET
    Réponses: 15
    Dernier message: 11/04/2008, 00h41
  5. Réponses: 1
    Dernier message: 31/08/2007, 10h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo