Précédent   Forum du club des développeurs et IT Pro > Environnements de développement > Autres EDI > MPLAB
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 11/11/2010, 17h53   #1
sylvain-ecvf
Invité de passage
 
Inscription : 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.
sylvain-ecvf est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/11/2010, 18h06   #2
Sve@r
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 495
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 45
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 : 3 495
Points : 6 604
Points : 6 604
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
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/11/2010, 19h59   #3
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 434
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 434
Points : 12 955
Points : 12 955
@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)
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 13/11/2010, 10h41   #4
Sve@r
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 495
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 45
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 : 3 495
Points : 6 604
Points : 6 604
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
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2010, 11h35   #5
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 434
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 434
Points : 12 955
Points : 12 955
Citation:
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 !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 13/11/2010, 11h59   #6
Jean-Marc.Bourguet
Expert Confirmé Sénior

 
Inscription : novembre 2005
Messages : 4 970
Détails du profil
Informations forums :
Inscription : novembre 2005
Messages : 4 970
Points : 5 607
Points : 5 607
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.
Jean-Marc.Bourguet est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 13/11/2010, 16h18   #7
Sve@r
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 495
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 45
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 : 3 495
Points : 6 604
Points : 6 604
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
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2010, 16h47   #8
Jean-Marc.Bourguet
Expert Confirmé Sénior

 
Inscription : novembre 2005
Messages : 4 970
Détails du profil
Informations forums :
Inscription : novembre 2005
Messages : 4 970
Points : 5 607
Points : 5 607
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.
Jean-Marc.Bourguet est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 16/11/2010, 22h35   #9
Sve@r
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 495
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 45
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 : 3 495
Points : 6 604
Points : 6 604
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
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2010, 08h37   #10
Jean-Marc.Bourguet
Expert Confirmé Sénior

 
Inscription : novembre 2005
Messages : 4 970
Détails du profil
Informations forums :
Inscription : novembre 2005
Messages : 4 970
Points : 5 607
Points : 5 607
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.
Jean-Marc.Bourguet est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 17/11/2010, 16h56   #11
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 434
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 434
Points : 12 955
Points : 12 955
@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;
....
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2010, 17h10   #12
Jean-Marc.Bourguet
Expert Confirmé Sénior

 
Inscription : novembre 2005
Messages : 4 970
Détails du profil
Informations forums :
Inscription : novembre 2005
Messages : 4 970
Points : 5 607
Points : 5 607
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.

Citation:
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.
Jean-Marc.Bourguet est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 17/11/2010, 23h43   #13
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 434
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 434
Points : 12 955
Points : 12 955
@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 !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/11/2010, 20h39   #14
dancingmad
Membre habitué
 
Homme Martin Bousquet
Développeur de jeux vidéo
Inscription : octobre 2008
Messages : 93
Détails du profil
Informations personnelles :
Nom : Homme Martin Bousquet
Âge : 25
Localisation : France, Paris (Île de France)

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

Informations forums :
Inscription : octobre 2008
Messages : 93
Points : 108
Points : 108
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 ?
dancingmad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2010, 10h20   #15
Jean-Marc.Bourguet
Expert Confirmé Sénior

 
Inscription : novembre 2005
Messages : 4 970
Détails du profil
Informations forums :
Inscription : novembre 2005
Messages : 4 970
Points : 5 607
Points : 5 607
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.
Jean-Marc.Bourguet est déconnecté   Envoyer un message privé Réponse avec citation 10
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 03h25.


 
 
 
 
Partenaires

Hébergement Web