Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 15 sur 15
  1. #1
    Invité de passage
    Inscrit en
    septembre 2008
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : septembre 2008
    Messages : 4
    Points : 0
    Points
    0

    Par défaut Recopier 4 char dans un float

    Bonjour,

    Je travaille sur un projet sur un PIC18f4550 sous MPLAB avec un compilateur C18. Je recois 4 octets de type char. Je voudrais recopier (bit a bit car les 4 octets char sont déjà au format float : 1 bit de signe + 8 bits d'exposant + 23 bit de valeurs) ces 4 octets char dans un float. Je n'arrive à rien de bon car j'ai un niveau basique en C. J'ai vraiment besoin d'un coup de main svp.

    Merci d'avance.

  2. #2
    Expert Confirmé Sénior
    Avatar de Sve@r
    Homme Profil pro Frédéric
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    4 531
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric
    Âge : 46
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 4 531
    Points : 10 141
    Points
    10 141

    Par défaut

    Citation Envoyé par sylvain-ecvf Voir le message
    Bonjour,

    Je travaille sur un projet sur un PIC18f4550 sous MPLAB avec un compilateur C18. Je recois 4 octets de type char. Je voudrais recopier (bit a bit car les 4 octets char sont déjà au format float : 1 bit de signe + 8 bits d'exposant + 23 bit de valeurs) ces 4 octets char dans un float. Je n'arrive à rien de bon car j'ai un niveau basique en C. J'ai vraiment besoin d'un coup de main svp.

    Merci d'avance.
    En admettant que tes 4 char fassent vraiment un float (c.a.d. en faisant abstraction des problèmes d'endianness), t'as plusieurs solutions. Tu peux jouer avec les masques et décalages de bits

    Code c :
    1
    2
    3
    4
    char a, b, c, d;
    float f;
     
    f=(a << 24) | (b << 16) | (c << 8) | d;

    Ou bien utiliser une union (qui a tous ces membres au même emplacement mémoire)

    Code c :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    union {
        char tab[4];
        float f;
    } mix;
     
    char a, b, c, d;
    float f;
     
    mix.tab[0]=a;
    mix.tab[1]=b;
    mix.tab[2]=c;
    mix.tab[3]=d;
     
    f=mix.f;
    Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
    Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
    Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
    Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
    Dr. Adrian Rogers (1931-2005)

  3. #3
    Expert Confirmé Sénior

    Homme Profil pro Patrick Gonord
    Enseignant Chercheur
    Inscrit en
    juin 2005
    Messages
    5 664
    Détails du profil
    Informations personnelles :
    Nom : Homme Patrick Gonord
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : juin 2005
    Messages : 5 664
    Points : 13 489
    Points
    13 489

    Par défaut

    @Sve@r :
    La première méthode ne peut pas marcher :
    Code :
    f=(a << 24) | (b << 16) | (c << 8) | d;
    Le second membre est construit comme un entier dont la représentation binaire est celle attendue. Par contre, l'assignation à un flottant ne conserve pas la représentation binaire, mais la valeur entière.

    Une alternative à la seconde méthode :
    Code :
    1
    2
    unsigned int u = (a << 24) | (b << 16) | (c << 8) | d;
    float f = *(float*)&u;
    (en mettant dans tous les cas, a, b, c et d dans le bon ordre)

  4. #4
    Expert Confirmé Sénior
    Avatar de Sve@r
    Homme Profil pro Frédéric
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    4 531
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric
    Âge : 46
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 4 531
    Points : 10 141
    Points
    10 141

    Par défaut

    Citation Envoyé par diogene Voir le message
    @Sve@r :
    La première méthode ne peut pas marcher :
    Code :
    f=(a << 24) | (b << 16) | (c << 8) | d;
    Le second membre est construit comme un entier dont la représentation binaire est celle attendue. Par contre, l'assignation à un flottant ne conserve pas la représentation binaire, mais la valeur entière.
    Exact. Me semblait bien en tapant cet exemple que j'avais oublié un truc important => le cast implicite

    Citation Envoyé par diogene Voir le message
    Une alternative à la seconde méthode :
    Code :
    1
    2
    unsigned int u = (a << 24) | (b << 16) | (c << 8) | d;
    float f = *(float*)&u;
    (en mettant dans tous les cas, a, b, c et d dans le bon ordre)
    Ouais mais non, c'est le même problème.
    L'opération int u=... va recoder tous les octets a, b, c et d dans le format int avec risque de mélange des bits selon le codage little-endian/big-endian. Puis le contenu de l'adresse prise comme adresse de float sera claqué dans le float mais ce sera trop tard. On aura déjà perdu le codage intrinsèque d'un float (mantisse, exposant etc...)
    Et même si par miracle on le garde, ce ne sera ni pérenne (le codage float peut ensuite changer) ni portable.

    La solution union fonctionne. Et à mon avis c'est la seule possible.
    Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
    Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
    Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
    Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
    Dr. Adrian Rogers (1931-2005)

  5. #5
    Expert Confirmé Sénior

    Homme Profil pro Patrick Gonord
    Enseignant Chercheur
    Inscrit en
    juin 2005
    Messages
    5 664
    Détails du profil
    Informations personnelles :
    Nom : Homme Patrick Gonord
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : juin 2005
    Messages : 5 664
    Points : 13 489
    Points
    13 489

    Par défaut

    Puis le contenu de l'adresse prise comme adresse de float sera claqué dans le float mais ce sera trop tard
    Non.
    Dans cette opération, la représentation binaire de f sera celle de u.
    Evidemment, il faut qu'on ait reconstitué correctement la représentation binaire du float (que ce soit dans l'unsigned int u ou dans le tableau tab de l'union); cette reconstitution correcte est une obligation quelle que soit la méthode utilisée. Evidemment, cette étape de reconstitution ne pourra jamais être portable et dépend du codage des float.

    Sinon, les deux méthodes pour passer de la représentation binaire stockée dans un entier ou dans un tableau de char en la valeur d'un float sont fondamentalement identique : Dans le cas de l'union, elle est basée sur le fait que, grace à l'union, l'adresse de départ du tableau est (implicitement) l'adresse du float ; dans le cas de l'unsigned int, on dit (explicitement) que l'adresse de l'unsigned int est l'adresse d'un float.

  6. #6
    Expert Confirmé Sénior

    Inscrit en
    novembre 2005
    Messages
    5 103
    Détails du profil
    Informations forums :
    Inscription : novembre 2005
    Messages : 5 103
    Points : 6 707
    Points
    6 707

    Par défaut

    Et les deux méthodes sont des comportement indéfinis. Variantes qui ne peuvent l'être que pour des raisons de représentation:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char tab[4];
    tab[0] = a; tab[1] = b; tab[2] = c; tab[3] = d;
    unsigned int u = (a << 24) | (b << 16) | (c << 8) | d;
    float f;
    assert(sizeof tab = sizeof f);
    assert(sizeof u == sizeof f);
    memcpy(&f, &u, sizeof f);
    memcpy(&f, tab, sizeof f);
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  7. #7
    Expert Confirmé Sénior
    Avatar de Sve@r
    Homme Profil pro Frédéric
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    4 531
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric
    Âge : 46
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 4 531
    Points : 10 141
    Points
    10 141

    Par défaut

    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Variantes qui ne peuvent l'être que pour des raisons de représentation:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char tab[4];
    tab[0] = a; tab[1] = b; tab[2] = c; tab[3] = d;
    unsigned int u = (a << 24) | (b << 16) | (c << 8) | d;
    float f;
    assert(sizeof tab = sizeof f);
    assert(sizeof u == sizeof f);
    memcpy(&f, &u, sizeof f);
    memcpy(&f, tab, sizeof f);
    memcpy => superbe. On aurait dû y penser !!!

    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Et les deux méthodes sont des comportement indéfinis.
    Là je ne pige pas trop. Bon, la solution mix des bits me semble en effet très aléatoire. Mais la solution union me semble correcte non ? (dans l'hypothèse évidente où a, b, c et d sont super bien formatés quoi)...
    Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
    Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
    Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
    Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
    Dr. Adrian Rogers (1931-2005)

  8. #8
    Expert Confirmé Sénior

    Inscrit en
    novembre 2005
    Messages
    5 103
    Détails du profil
    Informations forums :
    Inscription : novembre 2005
    Messages : 5 103
    Points : 6 707
    Points
    6 707

    Par défaut

    Citation Envoyé par Sve@r Voir le message
    memcpy => superbe. On aurait dû y penser !!!


    Là je ne pige pas trop. Bon, la solution mix des bits me semble en effet très aléatoire. Mais la solution union me semble correcte non ? (dans l'hypothèse évidente où a, b, c et d sont super bien formatés quoi)...
    Lire autre chose que le dernier champs écrit d'une union est un comportement indéfini. Le type prunning aussi (en gros même chose que pour les unions: on ne peut lire que le dernier type écrit -- sauf qu'on peut lire/écrire des chars). Le risque n'est pas tant un comportement bizarre de l'architecture que l'intervention des optimiseurs qui utilisent ces interdictions pour éviter de recharger des choses dans les registres... Comme ces techniques sont quand même d'un usage assez courant, certains essayent de les détecter et d'agir comme désiré, mais si c'est un peu trop subtil pour le code de détection, c'est fichu.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  9. #9
    Expert Confirmé Sénior
    Avatar de Sve@r
    Homme Profil pro Frédéric
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    4 531
    Détails du profil
    Informations personnelles :
    Nom : Homme Frédéric
    Âge : 46
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 4 531
    Points : 10 141
    Points
    10 141

    Par défaut

    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Lire autre chose que le dernier champs écrit d'une union est un comportement indéfini.
    Joli. On en apprend tous les jours !!!
    Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
    Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
    Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
    Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
    Dr. Adrian Rogers (1931-2005)

  10. #10
    Expert Confirmé Sénior

    Inscrit en
    novembre 2005
    Messages
    5 103
    Détails du profil
    Informations forums :
    Inscription : novembre 2005
    Messages : 5 103
    Points : 6 707
    Points
    6 707

    Par défaut

    Si tu veux, il y a plus sur ce sujet...

    Si le dernier membre ecrit est une structure et qu'il y a d'autres structures dans l'union partageant une sequence initiale de membres, on peut lire cette sequence initiale a travers ces autres structures.

    Et puis je remarque qu'on est en C et pas en C++. En C89, lire un autre membre que le dernier ecrit est un comportement defini par l'implementation, pas indefini. En C99, les bytes autres que les derniers ecrits sont indefinis, mais la partie partagee avec le dernier membre ecrit est reinterpretee.

    Donc le cas present est l'utilisation de l'union a un comportement indefini en C++, defini par l'implementation en C89 et equivalent au memcpy en C99. Sauf erreur de ma part, c'est un peu tordu ce machin.

    (L'utilisation de pointeurs est inedefini dans tous les cas et memcpy fait ce qui est desire dans tous les cas, ca me semble toujours la solution la plus simple).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  11. #11
    Expert Confirmé Sénior

    Homme Profil pro Patrick Gonord
    Enseignant Chercheur
    Inscrit en
    juin 2005
    Messages
    5 664
    Détails du profil
    Informations personnelles :
    Nom : Homme Patrick Gonord
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : juin 2005
    Messages : 5 664
    Points : 13 489
    Points
    13 489

    Par défaut

    @Jean-Marc
    Puisqu'on est sur le sujet des transtypages de pointeurs, peux-tu me dire si ces 8 propositions te semblent correctes ?

    En notant :
    - collectivement Tchar l'un des types char, unsigned char et signed char
    - TX et TY deux types différents et différents d'un Tchar et de void :

    1- TX * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.
    2- Tchar * -> TX * : comportement indéfini si TX peut n'être pas aligné sur l'alignement de Tchar.
    3- TX * -> Tchar * : valide
    4- TX * -> Tchar * -> TX * : valide
    5- TX * -> Tchar * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.

    6- TX * -> void * : valide
    7- TX * -> void * -> TX * : valide
    8- TX * -> void * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.

    Sans remettre en cause les autres solutions apportées, ceci devrait alors être correct :
    Code :
    1
    2
    3
    4
    float f;
    char *p = (char*)&f;
    p[0] = a;
    ....

  12. #12
    Expert Confirmé Sénior

    Inscrit en
    novembre 2005
    Messages
    5 103
    Détails du profil
    Informations forums :
    Inscription : novembre 2005
    Messages : 5 103
    Points : 6 707
    Points
    6 707

    Par défaut

    Citation Envoyé par diogene Voir le message
    @Jean-Marc
    Puisqu'on est sur le sujet des transtypages de pointeurs, peux-tu me dire si ces 8 propositions te semblent correctes ?

    En notant :
    - collectivement Tchar l'un des types char, unsigned char et signed char
    - TX et TY deux types différents et différents d'un Tchar et de void :

    1- TX * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.
    2- Tchar * -> TX * : comportement indéfini si TX peut n'être pas aligné sur l'alignement de Tchar.
    3- TX * -> Tchar * : valide
    4- TX * -> Tchar * -> TX * : valide
    5- TX * -> Tchar * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.
    6- TX * -> void * : valide
    7- TX * -> void * -> TX * : valide
    8- TX * -> void * -> TY * : comportement indéfini si TY peut n'être pas aligné sur l'alignement de TX.
    Oui. Mais, cf -fstrict-aliasing, meme quand les TX* <-> TY* sont definis, faire acces a la memoire avec un type autre que le dernier ecrit ou char est indefini.

    Sans remettre en cause les autres solutions apportées, ceci devrait alors être correct :
    Code :
    1
    2
    3
    4
    float f;
    char *p = (char*)&f;
    p[0] = a;
    ....
    C'est correct parce que char est particulier.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Expert Confirmé Sénior

    Homme Profil pro Patrick Gonord
    Enseignant Chercheur
    Inscrit en
    juin 2005
    Messages
    5 664
    Détails du profil
    Informations personnelles :
    Nom : Homme Patrick Gonord
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : juin 2005
    Messages : 5 664
    Points : 13 489
    Points
    13 489

    Par défaut

    @Jean-Marc
    Merci pour toutes ces précisions.

  14. #14
    Membre habitué
    Homme Profil pro Martin Bousquet
    Développeur de jeux vidéo
    Inscrit en
    octobre 2008
    Messages
    104
    Détails du profil
    Informations personnelles :
    Nom : Homme Martin Bousquet
    Âge : 27
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : octobre 2008
    Messages : 104
    Points : 118
    Points
    118

    Par défaut

    Dans le même genre, en considérant l'union suivante :

    Code :
    1
    2
    3
    4
    union {
      int[9] m,
      struct{ int m11,m12,m13,m21,m22,m23,m31,m32,m33} m2
    } matrix;
    Peut-on lire et écrire des champs de m après après avoir lu/écrit ces champs avec m2 ? Par exemple :

    Code :
    1
    2
    matrix.m[0 ] = 6;
    //matrix.m2.m11 == 6 ?

  15. #15
    Expert Confirmé Sénior

    Inscrit en
    novembre 2005
    Messages
    5 103
    Détails du profil
    Informations forums :
    Inscription : novembre 2005
    Messages : 5 103
    Points : 6 707
    Points
    6 707

    Par défaut

    Citation Envoyé par dancingmad Voir le message
    Dans le même genre, en considérant l'union suivante :

    Code :
    1
    2
    3
    4
    union {
      int[9] m,
      struct{ int m11,m12,m13,m21,m22,m23,m31,m32,m33} m2
    } matrix;
    Peut-on lire et écrire des champs de m après après avoir lu/écrit ces champs avec m2 ? Par exemple :

    Code :
    1
    2
    matrix.m[0 ] = 6;
    //matrix.m2.m11 == 6 ?
    Indéfini en C++. Défini par l'implémentation en C90 (puisqu'on accède à un champs différent d'une union que le dernier écrit) comme en C99 (ça dépend de comment l'implémentation arrange les champs m2, en pratique j'ai du mal à penser à une raison justifiant de mettre du padding entre deux champs de même type).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •