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 :

conversion de bit en int, float, char, etc.


Sujet :

C

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut conversion de bit en int, float, char, etc.
    Bonjour.
    Je dois lire des données dans un fichier de type binaire, et en extraire des informations à convertir en int, float ou char et les stocker dans une structure. Le problème c'est que je n'ai aucune idée de comment convertir par exemple 4 bytes en un int...

    Concrètement, j'ai un fichier avec des entrées de 50 bytes chacune (les entrées sont identiques).
    Les 4 premiers bytes représentent un int*,
    les 7 bytes de 8 à 14 des char,
    les bytes 18 à 21 sont un float*,
    de 30 à 37 des char,
    puis bytes 40 à 42 3 char...

    Grosso modo je veux lire le fichier, obtenir pour chaque entrée les 5 informations ci-dessus pour après les stocker dans une structure...
    Avez-vous une idée de comment je dois m'y prendre? Pour le moment, je sais seulement que fread permet de lire les fichiers mais je connais pas les opérations sur les bytes pour les convertir en types primitifs (char, int, etc...)...
    Merci d'avance !

    PS: j'ai essayé de mettre en PJ le fichier mais je crois que ce n'est pas possible de mettre des fichiers binaires...

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    Bonjour,

    Il suffit de lire les informations les unes après les autres :

    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
    int * param_1;
    char param_2[7];
    float * param_3;
     
    /* on s'assure que les types font bien la taille attendue */
    ASSERT(4 == sizeof param_1);
    ASSERT(7 == sizeof param_2);
    ASSERT(4 == sizeof param_3);
     
    /* ouverture du fichier */
    FILE *f = fopen("..." , "rb");
     
     
    if(NULL == f) {
        perror("...");
    } else {
        /* lecture des paramètres */
        fread(&param_1, sizeof param_1, 1, f);
     
        fread(param_2, sizeof *param_2, 7, f);
     
        fread(&param_3, sizeof param_3, 1, f);
    }
    Attention,
    • je ne tiens pas compte de l'endianness ici.
    • Un int* sortit de son contexte ne sert pas à grand chose, ne sommes nous pas devant un cas d'un tableau mal enregistré dans un fichier ?
    • Les format d'échanges binaires sont souvent source de problème, il ne faut pas hésiter à utiliser du format texte.


    On pourrait aussi faire en une fois avec une structure. Mais dans ce cas là, on s'expose aux problèmes d'alignement qui n'est pas forcement les mêmes d'un compilateur à l'autre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct params {
        int * p_1;
        char p_2[7];
        float * p_3;
    };
     
    struct params mes_params;
    fread(&mes_params, sizeof mes_params, 1, f);

  3. #3
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par mabu Voir le message
    Bonjour,

    Il suffit de lire les informations les unes après les autres :

    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
    int * param_1;
    char param_2[7];
    float * param_3;
     
    /* on s'assure que les types font bien la taille attendue */
    ASSERT(4 == sizeof param_1);
    ASSERT(7 == sizeof param_2);
    ASSERT(4 == sizeof param_3);
     
    /* ouverture du fichier */
    FILE *f = fopen("..." , "rb");
     
     
    if(NULL == f) {
        perror("...");
    } else {
        /* lecture des paramètres */
        fread(&param_1, sizeof param_1, 1, f);
     
        fread(param_2, sizeof *param_2, 7, f);
     
        fread(&param_3, sizeof param_3, 1, f);
    }
    Dans ce cas, comme dans celui de la structure, j'imagine qu'on suppose que les informations se succèdent?... C'est à dire qu'après avoir lu le premier int*, les bytes suivant sont les 7 char. Or dans mon cas, les byte 1 à 4 sont le int*, puis c'est dans les bytes 7 à 14 qu'il y a des char puis encore 2 bytes "vides", etc... Le format text de ce que je veux lire est:
    1|AtulBat|4.8281|9MCS8255|34.4

    Citation Envoyé par mabu Voir le message
    Attention,
    • je ne tiens pas compte de l'endianness ici.
    • Un int* sortit de son contexte ne sert pas à grand chose, ne sommes nous pas devant un cas d'un tableau mal enregistré dans un fichier ?
    • Les format d'échanges binaires sont souvent source de problème, il ne faut pas hésiter à utiliser du format texte.
    J'ai pas bien compris de quoi s'agissait l'endianness, je regarderais ça si ce que je test ne marche pas.
    Pour le int* et le format binaire, je suis d'accord mais c'est dans le cadre d'un devoir et les formats sont imposés.

  4. #4
    Invité(e)
    Invité(e)
    Par défaut
    Dans ce cas, comme dans celui de la structure, j'imagine qu'on suppose que les informations se succèdent?... C'est à dire qu'après avoir lu le premier int*, les bytes suivant sont les 7 char. Or dans mon cas, les byte 1 à 4 sont le int*, puis c'est dans les bytes 7 à 14 qu'il y a des char puis encore 2 bytes "vides", etc...
    Oui effectivement, j'ai lu trop vite...

    Correction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        int i;
        /* lecture du premier int * */
        fread(&param_1, sizeof param_1, 1, f);
     
        /* on saute X octets */
        for(i = 0; i < X; ++i) {
            fgetc(f);
        }
     
        /* lecture des char */ 
        fread(param_2, sizeof *param_2, 7, f);
    Le format text de ce que je veux lire est:
    1|AtulBat|4.8281|9MCS8255|34.4
    Mais on est bien d'accord, ton fichier est du binaire ?

  5. #5
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par mabu Voir le message
    Oui effectivement, j'ai lu trop vite...

    Correction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        int i;
        /* lecture du premier int * */
        fread(&param_1, sizeof param_1, 1, f);
     
        /* on saute X octets */
        for(i = 0; i < X; ++i) {
            fgetc(f);
        }
     
        /* lecture des char */ 
        fread(param_2, sizeof *param_2, 7, f);
    Mais on est bien d'accord, ton fichier est du binaire ?
    Ok merci. oui oui le fichier est bien en binaire, c'est juste que j'ai le résultat de la première entrée pour m'assurer que je lit bien.

    J'ai fait ce que tu m'as dit mais par contre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int* param_1;
     
    FILE* file = fopen("../testfiles/test1.dat","r");
    if(file){
        fread(&param_1, sizeof param_1, 4, file);
        printf("param_1: %i\n",*param_1);
    }
    J'ai un souci là. déjà dans le fread, si je comprend bien, tu stock le premier parametre dans l'@ de param_1? du coup pour accéder à la valeur pointé j'ai essayé de déréférencer et ça plante. du coup si je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("param_1: %i\n",param_1);
    ca marche mais ça me renvoie une adresse mémoire et non l'int qui est pointé (ici en l'occurence c'est 1)...

  6. #6
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par mabu Voir le message
    Oui effectivement, j'ai lu trop vite...

    Correction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        int i;
        /* lecture du premier int * */
        fread(&param_1, sizeof param_1, 1, f);
     
        /* on saute X octets */
        for(i = 0; i < X; ++i) {
            fgetc(f);
        }
     
        /* lecture des char */ 
        fread(param_2, sizeof *param_2, 7, f);
    Mais on est bien d'accord, ton fichier est du binaire ?
    ps: mon programme bug au niveau du fgetc. Le faire tout seul, pas de problème mais par contre après le fread, ça plante...

  7. #7
    Invité(e)
    Invité(e)
    Par défaut
    Citation Envoyé par ncheboi Voir le message
    J'ai fait ce que tu m'as dit mais par contre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fread(&param_1, sizeof param_1, 4, file);
    Non, ici tu demande à lire 4 fois des données de taille sizeof param_1, tu lis donc 4 fois trop de données.
    Relis la doc de fread.

    Citation Envoyé par ncheboi Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("param_1: %i\n",param_1);
    ca marche mais ça me renvoie une adresse mémoire et non l'int qui est pointé (ici en l'occurence c'est 1)
    Que vaut l'adresse mémoire ? Peux tu faire un dump hexadécimal des 20 premiers octets du fichier à lire ?

    Citation Envoyé par ncheboi Voir le message
    ps: mon programme bug au niveau du fgetc. Le faire tout seul, pas de problème mais par contre après le fread, ça plante...
    Que vaut X ?
    Décris le bug.

  8. #8
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        FILE* file = fopen("../testfiles/test1.dat","r");
        if(file){
            fread(&param_1, sizeof param_1, 1, file);
            for(i = 0; i < 2; ++i) {
                fgetc(file);
            }
            fread(name, sizeof(char),2,file);
            printf("param_1: %i\n",param_1);
            printf("name: %c\n",name[8]);
        }
    J'ai modifié le code. Voici ce que je reçois en sortie:
    param_1: 16777216
    name:

    (rien pour le name...

    Voici le dump hexadecimal:

    00 00 00 01 00 00 00 p y k u m a r 00 00 00 A 06 f f 00 00 00 00 00 00 00 00 2 0 0 9 M C S 2 3 4 2 3 2 00 00 00 00 00 00 00 00
    00 00 00 01 00 00 00 70 79 6b 75 6d 61 72 00 00 00 41 06 66 66 00 00 00 00 00 00 00 00 32 30 30 39 4d 43 53 32 33 34 32 33 32 00 00 00 00 00 00 00 00
    00 00 00 01 00 00 00 a l k u m a r 00 00 00 @ é ™ š 00 00 00 00 00 00 00 00 2 0 0 9 M C S 1 2 3 2 5 6 00 00 00 00 00 00 00 00
    00 00 00 01 00 00 00 61 6c 6b 75 6d 61 72 00 00 00 40 e9 99 9a 00 00 00 00 00 00 00 00 32 30 30 39 4d 43 53 31 32 33 32 35 36 00 00 00 00 00 00 00 00
    00 00 00 02 00 00 00 a l k u m a r 00 00 00 @ é ™ š 00 00 00 00 00 00 00 00 2 0 0 9 M C S 1 2 3 2 5 6 00 00 00 00 00 00 00 00
    00 00 00 02 00 00 00 61 6c 6b 75 6d 61 72 00 00 00 40 e9 99 9a 00 00 00 00 00 00 00 00 32 30 30 39 4d 43 53 31 32 33 32 35 36 00 00 00 00 00 00 00 00.. (je l'ai fait avec le site: http://www3.amherst.edu)

  9. #9
    Invité(e)
    Invité(e)
    Par défaut
    Le problème n'est pas trivial.

    Quand on travaille sur un processeur intel sur windows, quand on écrit un entier dans un fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int entier = 1;
    fwrite(&entier, sizeof entier, 1, fichier)
    On obtient : Or ton fichier commence par Petites questions :
    • ton devoir est il plus précis quant tu format du fichier ?
    • sur quelle(s) architecture(s) travailles tu ?


    Sinon, pour lire un tel fichier de manière portable, on peut lire octet à octet :

    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
    /* octect lu */
    int tmp;
     
    /* premier parametre */
    int param_1 = 0;
     
    /*second parametre */
    char param_2[7+1] = "";
     
    FILE *f = fopen(..., "rb");
     
    /* lecture du premier parametre */
    for(i = 0; i < 4; ++i) {
        param_1 <<= 8;
        tmp = fgetc(f);
        param_1 |= tmp;
    }
    /* sauter 3 octets */
    for(i = 0; i < 3; ++i) {
        fgetc(f);
    }
    /* second parametre */
    for(i = 0; i < 7; ++i) {
        param[i] = fgetc(f);
    }

  10. #10
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par mabu Voir le message
    Le problème n'est pas trivial.

    Quand on travaille sur un processeur intel sur windows, quand on écrit un entier dans un fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int entier = 1;
    fwrite(&entier, sizeof entier, 1, fichier)
    On obtient : Or ton fichier commence par Petites questions :
    • ton devoir est il plus précis quant tu format du fichier ?
    • sur quelle(s) architecture(s) travailles tu ?


    Sinon, pour lire un tel fichier de manière portable, on peut lire octet à octet :

    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
    /* octect lu */
    int tmp;
     
    /* premier parametre */
    int param_1 = 0;
     
    /*second parametre */
    char param_2[7+1] = "";
     
    FILE *f = fopen(..., "rb");
     
    /* lecture du premier parametre */
    for(i = 0; i < 4; ++i) {
        param_1 <<= 8;
        tmp = fgetc(f);
        param_1 |= tmp;
    }
    /* sauter 3 octets */
    for(i = 0; i < 3; ++i) {
        fgetc(f);
    }
    /* second parametre */
    for(i = 0; i < 7; ++i) {
        param[i] = fgetc(f);
    }
    Ok. Au niveau des premiers bytes, peut etre que le début 00 00 00 c'est un espace... Je sais pas j'ai vraiment aucune info de plus sur le format. sinon je comprends pas ce que tu fais pour obtenir le param_1... (<<=, |=)...

  11. #11
    Invité(e)
    Invité(e)
    Par défaut
    Citation Envoyé par ncheboi Voir le message
    Je sais pas j'ai vraiment aucune info de plus sur le format.
    C'est un format définit par le prof pour le devoir ? Un format particulier ?

    Au niveau des premiers bytes, peut etre que le début 00 00 00 c'est un espace...
    Dans ce cas le problème sera bien plus simple, il faudrait reprendre le premier code ( à base de fread) et sauter 3 octets avant de lire le premier entier plutôt qu'après.

    Citation Envoyé par ncheboi Voir le message
    sinon je comprends pas ce que tu fais pour obtenir le param_1... (<<=, |=)...
    Oui en en plus j'y ai fait une bêtise. (me suis trompé d'endianness)

    L'operateur <<= permet de décaler un nombre à gauche.
    L'operateur|= permet de faire un ou binaire.

    Supposons qu'on veuille lire dans un fichier "01 02 03 04" l'entier à reconstituer est 0x04030201.

    L'idée est de prendre les 4 octets qui nous intéressent depuis le fichier et de les copier dans l'entier à l'endroit où ça nous intéresse.
    Entrées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    0x01 00000001
    0x02 00000010
    0x03 00000011
    0x04 00000100
    Sortie voulue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00000100 00000011 00000010 00000001
    On va donc lire le premier octet depuis le fichier 0x01 et le placer là où il faut dans l'entier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    tmp = fgetc(f);
    param_1 |= tmp;
    On lit le second octet depuis le fichier et on le place dans l'entier, mais on ne veut pas le placer m'importe où : il faut le décaler de 8 bits pour qu'il est un sens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    tmp = fgetc(f);
    tmp <<= 8; 
    /* tmp passe de 
    00000000 00000000 00000000 00000010 
    à 
    00000000 00000000 00000010 00000000 */
    param_1 |= tmp;
    /* après cette manip, param_1 vaut 
    00000000 00000000 00000010 00000001*/
    Même chose pour le troisième octet qu'on va décaler de 16 bits.
    Même chose pour le quatrième octet qu'on va décaler de 24 bits.

    On peut donc écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(i = 0; i < 4; ++i) {
        tmp = fgetc(f);
        tmp <<= (8*i);
        param_1 |= tmp;
    }

  12. #12
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Espagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 145
    Points : 77
    Points
    77
    Par défaut
    Bon. Je viens de me rendre compte que j'avais mal lu les instructions. Les premier byte du fichier correspond bien à un int et non un int* (enfin après avoir passé le 00 00 00 du début de chaque ligne).
    Du coup si je comprend bien 01 00 00 00 vaut 1 et 02 00 00 00 vaut 2 ?...

    Maintenant pour lire je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int key;
    FILE* file = fopen("../testfiles/test1.dat","r");
    if(file){
        for(i = 0; i < 3; ++i) {
            fgetc(file);
         }
         fread(key,sizeof key,1,file);
         printf("key = %i\n",key);
    }
    Ca me renvoie une @ mémoire et non le 1 comme souhaitais... Où est-ce que je me suis planté?

  13. #13
    Invité(e)
    Invité(e)
    Par défaut
    Citation Envoyé par ncheboi Voir le message
    Du coup si je comprend bien 01 00 00 00 vaut 1 et 02 00 00 00 vaut 2 ?...
    Oui, c'est ça, et 00 01 00 00 vaut 256.

    Citation Envoyé par ncheboi Voir le message
    Maintenant pour lire je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int key;
    FILE* file = fopen("../testfiles/test1.dat","r");
    if(file){
        for(i = 0; i < 3; ++i) {
            fgetc(file);
         }
         fread(key,sizeof key,1,file);
         printf("key = %i\n",key);
    }
    Ca me renvoie une @ mémoire et non le 1 comme souhaitais... Où est-ce que je me suis planté?
    • Attention à l'utilisation de fread !
    • Attention à ouvrir le fichier en mode binaire.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int key;
    FILE* file = fopen("../testfiles/test1.dat","rb");
    if(file){
        for(i = 0; i < 3; ++i) {
            fgetc(file);
         }
         fread(&key,sizeof key,1,file);
         printf("key = %i\n",key);
    }

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 09/05/2007, 13h35
  2. Réponses: 1
    Dernier message: 15/02/2007, 17h32
  3. Conversion int en char *
    Par Trunks dans le forum C
    Réponses: 6
    Dernier message: 18/03/2006, 16h44
  4. type d'un char* ? int, float .... ?
    Par stitch dans le forum C
    Réponses: 5
    Dernier message: 08/03/2006, 16h27
  5. [C++] Conversion de int en char* ou SetDlgItemText()
    Par lastcheper dans le forum MFC
    Réponses: 3
    Dernier message: 11/04/2005, 17h46

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