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 :

float et int dans une union


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    280
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 280
    Points : 149
    Points
    149
    Par défaut float et int dans une union
    Bonjour,

    Bon le programme est en C++ mais la question est valable tant pour le C que pour le C++ :
    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
    #include<iostream>
    using namespace std;
     
    union pack {
    	unsigned int a[2];
    	long l;
    	unsigned char b[8];
    	float f;
    };
     
    int main (){
    	pack p[10];
    	pack* pp=p;
    	cout << "Taille d'un pack : " << sizeof(pack)<<endl;
    	cout << "Taille d'un float : " << sizeof(float)<<endl;
    	(*p).l=0;
    	cout<<(*p).a[0]<<"\t"<<(*p).a[1]<<"\t"<<(*p).l<<endl;
    	(*p).a[0]=128;
    	(*p).b[7]=128;
    	cout<<hex << p<<" : "<<dec<< (*p).a[0]<<"\t\t"<<(*p).a[1]\
    		<<"\t"<<dec<<(*p).l<<"\t"<<(*p).f<<endl;
    	(*p).f=-4.128;
    	cout<<hex << p<<" : "<<dec<< (*p).a[0]<<"\t"<<(*p).a[1]\
    		<<"\t"<<dec<<(*p).l<<"\t"<<(*p).f<<endl;
    	(*p).a[0]=0;
    	cout<<hex << p<<" : "<<dec<< (*p).a[0]<<"\t\t"<<(*p).a[1]\
    		<<"\t"<<dec<<(*p).l<<"\t"<<(*p).f<<endl;
     
    }
    Voici le résultat du programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Taille d'un pack : 8
    Taille d'un float : 4
    0	0	0
    0x7fff6ec525d0 : 128		2147483648	-9223372036854775680	1.79366e-43
    0x7fff6ec525d0 : 3229882515	2147483648	-9223372033624893293	-4.128
    0x7fff6ec525d0 : 0		2147483648	-9223372036854775808	0
    Ma question :

    Pourquoi le premier octet du long l est le char b[7] alors que, apparemment, le premier octet du float f est b[0] ?
    On dirait que le float est placé à partir de la fin de l'union...
    Merci pour vos éclaircissement
    "Bien qu'on ait du coeur à l'ouvrage,
    L'Art est long et le Temps est court." - CB

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Salut

    Pourquoi le premier octet du long l est le char b[7] alors que, apparemment, le premier octet du float f est b[0] ?
    C'est lié au boutisme (endianess). En mémoire, les bytes ne sont pas forcément écrits dans l'ordre qu'on croit : http://fr.wikipedia.org/wiki/Endianness

    La variable membre de type "long" fait probablement la taille d'un "int". Dans ton code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    (*p).a[0]=128;
    	(*p).b[7]=128;
    	cout<<hex << p<<" : "<<dec<< (*p).a[0]<<"\t\t"<<(*p).a[1]\
    		<<"\t"<<dec<<(*p).l<<"\t"<<(*p).f<<endl;
    cela concerne "a[1]", qui correspond aux 4 derniers éléments de ton tableau de "unsigned char".
    En mettant le byte 7 de ton tableau de "unsigned char" à 127, si ta machine est en little endian, cela correspond effectivement à la valeur (sur ses 4 derniers bytes)

    127 * 256 ^ 3 + 0 * 256 ^ 2 + 0 * 256 ^ 1 + 0 * 256 ^ 0 = 2147483648

    et non à

    127 * 256 ^ 0 + 0 * 256 ^ 1 + 0 * 256 ^ 2 + 0 * 256 ^ 3 = 127

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    280
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 280
    Points : 149
    Points
    149
    Par défaut
    Citation Envoyé par jeroman Voir le message
    La variable membre de type "long" fait probablement la taille d'un "int".
    Ben non justement les long font 8, les int 4, les short 2 et les float 4 aussi...
    Ce qui m'etonne c'est le fait que ce soit le premier int (a[0]) qui est l'octet de poids fort du float alors que c'est le deuxième int (a[1] qui est celui de poids fort du long...
    C'est lié au boutisme (endianess). En mémoire, les bytes ne sont pas forcément écrits dans l'ordre qu'on croit : http://fr.wikipedia.org/wiki/Endianness
    Merci je vais lire ça...

    Salut !
    "Bien qu'on ait du coeur à l'ouvrage,
    L'Art est long et le Temps est court." - CB

  4. #4
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Ben non justement les long font 8, les int 4, les short 4 et les float 4 aussi...
    Tu parles en général ou sur ta machine ?
    La norme C n'impose pas la taille des types, mais seulement la taille minimale.
    http://c.developpez.com/faq/?page=ty...S_taille_types

    Ce qui m'etonne c'est le fait que ce soit le premier int (a[0]) qui est l'octet de poids fort du float alors que c'est le deuxième int (a[1] qui est celui de poids fort du long...
    Attention, les "float" et les "double" ne se codent absolument pas comme les types entiers. Voici la norme utilisée sur la plupart des machines : http://fr.wikipedia.org/wiki/IEEE_754

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    280
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 280
    Points : 149
    Points
    149
    Par défaut
    Citation Envoyé par jeroman Voir le message
    Tu parles en général ou sur ta machine ?
    Sur ma machine (Linux OpenSUSE sur une architecture AMD64).

    Attention, les "float" et les "double" ne se codent absolument pas comme les types entiers. Voici la norme utilisée sur la plupart des machines : http://fr.wikipedia.org/wiki/IEEE_754
    Oui ... Mais le bit de poids fort est le bit qui détermine le signe que ce soit en float ou en int.
    dans :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	(*p).f=-4.128;
    	cout<<hex << p<<" : "<<dec<< (*p).a[0]<<"\t"<<(*p).a[1]\
    		<<"\t"<<dec<<(*p).l<<"\t"<<(*p).f<<endl;
    le fait de mettre le float - 4.128 (donc son bit de poids fort à 1) modifie (*p).a[0].

    Par contre le fait de mettre (*p).b[7]=128 met le bit de poids fort de (*p).a[1] à 1 et à pour effet de rendre le long signé négatif. J'en déduis donc que (*p).b[7] est l'octet de poids fort de (*p).l ...

    C'est ça que je trouve étrange...


    Pour le endianness j'ai lu le wiki mais ce qui m'etonne encore plus c'est que je suis sur une architecture issue de X86 et que sur cette architecture c'est le big endian qui s'applique, or le comportement décrit ci-dessus ressemble davantage à du little endian.
    "Bien qu'on ait du coeur à l'ouvrage,
    L'Art est long et le Temps est court." - CB

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Dans l'ordre des choses, tu fais ceci :

    1) Tu remplis ta structure avec des bytes à 0, puis en mettant 127 dans le premier et dans le dernier élément du tableau "b".
    "l" est donc négatif, et son signe (ainsi que sa valeur) sera le même en little et en big endian, puisque ça se lira de la même manière dans un sens ou dans l'autre.
    Par contre, "f" sera positif en little endian (ce qui semble être le cas chez toi), et négatif en big endian ; et il n'aura pas la même valeur.

    2) Ensuite, tu donnes à "f" la valeur -4.128. Cela va forcément modifier a[0], les 4 premiers octets de "l" (en mémoire) et les 4 premiers éléments du tableau "b".
    -4.128 en little endian s'écrit comme ça en mémoire (en format binaire) : 10010011 00011000 10000100 11000000
    Et en big endian : 11000000 10000100 00011000 10010011
    Ca ne changera donc rien au signe de "l" (qui reste négatif), puisque b[7] est toujours à 128 (bit 7 à 1), et les bits 7 du 1er et du dernier octet de "f" (en mémoire) sont eux aussi à 1. Par conséquent, little ou big endian, le signe de "l" ne change pas. Par contre, sa valeur si.

    3) Tu mets a[0] à 0, ce qui remet b[0] à 0 et le premier octet (en mémoire) de "l" à 0 (bit 7 à 0).
    Donc, en big endian, "b" devient cette fois positif. Et en little endian, il reste négatif, ce qui se vérifie à nouveau chez toi.

    Sur ma machine, qui est en little endian, j'obtiens les mêmes valeurs que toi, après avoir adapté sur ma machine (qui est en 32 bits) et traduit en C.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    280
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 280
    Points : 149
    Points
    149
    Par défaut
    oui en effet little endian correspond au architectures x86...
    contrairement à ce que je dis dans mon post précédent... autant pour moi

    mais les tableaux commence par la fin on dirait...

    Je digère ton dernier post et je reviens ...

    @+
    "Bien qu'on ait du coeur à l'ouvrage,
    L'Art est long et le Temps est court." - CB

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    280
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 280
    Points : 149
    Points
    149
    Par défaut
    Ok ...
    J'ai eu un peu le temps de me repencher sur le problème de liliputien...

    Donc en fait ma confusion venait que je me pensais en big endian alors que c'était du little endian (X86)... Le premier elément de chaque tableau commence bien par le "début" de l'union, le float est bien lui aussi au "début" de l'union sauf que son octet de poids fort correspond au char b[3] (little endian).

    Merci pour tes explications.
    "Bien qu'on ait du coeur à l'ouvrage,
    L'Art est long et le Temps est court." - CB

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 27/11/2009, 20h37
  2. SUM dans une UNION
    Par sabotage dans le forum Langage SQL
    Réponses: 2
    Dernier message: 27/01/2008, 11h41
  3. problème de type dans une union [c#]
    Par maxdwarf dans le forum Windows Forms
    Réponses: 8
    Dernier message: 08/11/2007, 17h31
  4. Réponses: 19
    Dernier message: 04/06/2007, 17h12
  5. comment mettre des int dans une char??
    Par gronaze dans le forum C
    Réponses: 5
    Dernier message: 21/04/2006, 17h02

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