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

MPLAB Discussion :

Recopier 4 char dans un float


Sujet :

MPLAB

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 4
    Points : 5
    Points
    5
    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 éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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;
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    @Sve@r :
    La première méthode ne peut pas marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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)
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par diogene Voir le message
    @Sve@r :
    La première méthode ne peut pas marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    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.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  6. #6
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    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 éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    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 !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    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 éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    float f;
    char *p = (char*)&f;
    p[0] = a;
    ....
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    @Jean-Marc
    Merci pour toutes ces précisions.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  14. #14
    Membre averti
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2008
    Messages
    187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 187
    Points : 448
    Points
    448
    Par défaut
    Dans le même genre, en considérant l'union suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    matrix.m[0 ] = 6;
    //matrix.m2.m11 == 6 ?

  15. #15
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par dancingmad Voir le message
    Dans le même genre, en considérant l'union suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

Discussions similaires

  1. un char dans un float
    Par speedcore dans le forum C
    Réponses: 7
    Dernier message: 10/05/2006, 17h54
  2. Insertion d'un char dans un char *
    Par bugmenot dans le forum C
    Réponses: 2
    Dernier message: 22/10/2005, 16h17
  3. Changer un char dans une chaine
    Par Calaz dans le forum C
    Réponses: 10
    Dernier message: 07/10/2005, 14h32
  4. [SQL] Convertir un champ INT en CHAR dans un SELECT ?
    Par webtheque dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 17/03/2005, 15h45
  5. [Avancé] Recopie une session dans un autre client
    Par gregoun dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 29/06/2004, 13h11

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