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 :

Compresser et decompresser des structures


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Compresser et decompresser des structures
    Bonjour,

    J'ai besoin de passer d'une structure a un std::vector<char> et inversement.
    J'aimerais savoir si vous avez un moyen plus efficasse que le mien.

    struct -> vector
    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
    std::vector<char> &             MaClass::pack(maStruct * packet)
    {
      std::string                   myString;
      std::stringstream         myStream;
      std::vector<char>        *to_ret = new std::vector<char>;
     
      if (packet)
        {
          myStream << packet->infoA;
          myStream << packet->infoB;
     
          myString = myStream.str();
          for (unsigned int i = 0 ; i < myString.size() ; ++i)
            (*to_ret)[i] = myString[i];
        }
     
      return *to_ret;
    }
    vector -> struct
    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
    maStruct *                      MaClass::unpack(std::vector<char> & buffer)
    {
      std::string                    myString;
      std::stringstream          myStream;
      t_packet                      *to_ret = new t_packet;
     
     
      if (!buffer.empty())
        {
          myString.resize(buffer.size());
          for (unsigned int i = 0 ; i < buffer.size() ; ++i)
            myString[i] = buffer[i];
     
          myStream << myString.erase(0 , sizeof(to_ret->infoA));
          myStream >> to_ret->infoA;
          myStream.clear();
          myStream << myString.erase(0 , sizeof(to_ret->infoB));
          myStream >> to_ret->infoB;
          myStream.clear();
          return to_ret;
        }
      else
        delete to_ret;
      return NULL;
    }
    Dernière modification par Invité ; 07/12/2012 à 12h08.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Pourrais-tu nous montrer la déclaration de ta structure pour voir exactement ce qu'elle contient ?

    Sinon quel est le but de ton std::vector<char>, que vas-tu faire avec par la suite ?

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    dans l'ordre qui me vient à l'esprit
    - quelle idée saugrenue
    - d'où te vient ce "besoin" ?
    - quelle différence entre une std::string et un vector<char> ?
    - allocation dynamique d'un vector ?
    - fuite mémoire sûrement
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Je fait cela pour echanger des donnees avec un serveur via un protocol TCP.

    voici la structure:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct                          t_header
    {
            unsigned char   type;
            unsigned int    sender_id;
            unsigned int    receiver_id;
            unsigned int    info_length;
    };
     
    struct                          t_packet
    {
            t_header        header;
            char            data*;
    };
    Le fait de convertir la structure en vector<char> me permet d'avoir un typage lourd et (je n'en suis pas certin) d'eviter les problemes de big et little endian.
    Dernière modification par Invité ; 07/12/2012 à 14h33.

  5. #5
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Il y a des fonctions pour ne pas se soucier de cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    htons()
        Reorder the bytes of a 16-bit unsigned value from processor order to network order. The macro name can be read as "host to network short." 
    htonl()
        Reorder the bytes of a 32-bit unsigned value from processor order to network order. The macro name can be read as "host to network long."
    ntohs()
        Reorder the bytes of a 16-bit unsigned value from network order to processor order. The macro name can be read as "network to host short." 
    ntohl()
        Reorder the bytes of a 32-bit unsigned value from network order to processor order. The macro name can be read as "network to host long."

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Sinon, la seule chose qui l'assure c'est des spec à jour qui détaillent comment sont encodées les données.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Invité
    Invité(e)
    Par défaut
    J'ai essaye d'autres methodes que celle decrite au debut (et qui etait totallement non fonctionnelle), mais sans resultats convainquant.

    Je vais reformuler le probleme: j'ai besoin de passer d'une structure a une suite d'octets et inversement. Quelqu'un aurait il une methode ?

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Ce que tu veux se nomme la sérialisation. Selon les cas, ça peut être plus ou moins complexe.

    Si ta structure d'échange contient des pointeurs vers d'autres structures, des pointeurs sur classes dérivées... je te conseille de regarder vers boost.serialization.

    Si tu veux portabilité (entre machines, mais aussi entre langages) et compacité, j'ai entendu du bien de la bibliothèque de google nommée protobuf. Tu vas décrire ta structure d'échange dans un fichier exerne, pas écrit en C++, puis générer du code C++ à partir de ce format qui te permettra de sérialiser/désérialiser vers ce format.

    Si ça te semble une artillerie trop lourde pour un besoin ponctuel et ciblé, tu peux te faire une petite sérialisation (binaire en supposant que tu connaisse la taille de des données ou textuelle) à la main. Si tu veux un format binaire (probablement plus rapide), je te conseille déjà de travailler avec un vector<unsigned char> plus qu'un vector<char>, et d'utiliser des opération de manipulation de bits, comme >> (décalage) et & (et bit à bit) pour sérialiser, et << 'décalage) et | (ou bit à bit) pour désérialiser.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Poutchyouk Voir le message
    J'ai essaye d'autres methodes que celle decrite au debut (et qui etait totallement non fonctionnelle), mais sans resultats convainquant.

    Je vais reformuler le probleme: j'ai besoin de passer d'une structure a une suite d'octets et inversement. Quelqu'un aurait il une methode ?
    Une structure EST une suite d'octets. Le fait de caster un pointeur vers la structure en pointeur char* (avec reintrepret_cast<char*>(&structure)) le montre assez bien.

    La question n'est donc pas là, mais: qu'est-ce que tu va faire avec cette suite d'octets ? La stocker dans un fichier ? L'envoyer sur le réseau ? La transférer en mémoire ?

    En fonction de ton cas d'utilisation, alors la réponse que tu obtiendras ici sera différente.

    Si le but est, pour une raison inconnue, du stocker la structure dans un vector<char>, alors le code suivant est suffisant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char *p = reinterpret_cast<char*>(&structure);
    std::vector<char> v(p, p + sizeof(structure));
    Je ne dit pas que c'est la meilleure méthode (ça dépends vraiment de ce que tu veux faire, en fait).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  10. #10
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Si ça peut être utile, voici un petit code générique pour sérialiser des entiers non signés (en acceptant de perdre 1, 2 ou 3 bits au passage si l'entier est de 16, 32 ou 64 bits -> 15, 30 ou 61 bits).
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    //Serialization of unsigned integers of 16, 32 or 64 bits
     
    //16 bits (can't store more than 15 bits):
    // range [   0,   127] -> one byte
    // range [ 128, 32767] -> two bytes
    //
    //|c|xxxxxxx| |xxxxxxxx|
    // ^    7          8
    // 0 <--7-->
    // 1 <-------15------->
     
    //32 bits (can't store more than 30 bits):
    // range [       0,         63] -> one byte
    // range [      64,      16383] -> two bytes
    // range [   16384,    4194303] -> three bytes
    // range [ 4194304, 1073741823] -> four bytes
    //
    //|cc|xxxxxx| |xxxxxxxx| |xxxxxxxx| |xxxxxxxx|
    // ^^    6         8          8          8
    // 00 <--6->
    // 01 <-------14------>
    // 10 <------------22------------>
    // 11 <------------------30----------------->
     
    //64 bits (can't store more than 61 bits):
    // range [              0,             31] -> one byte
    // range [             32,           8191] -> two bytes
    // range [           8192,        2097151] -> three bytes
    // range [        2097152,      536870911] -> four bytes
    // range [      536870912,   137438953471] -> five bytes (up to 128 "Gigas")
    // range [   137438953472, 35184372088831] -> six bytes (up to 32768 "Gigas")
    // range [ 35184372088831,            ...] -> seven bytes (up to 8388608 "Gigas")
    // ...
    //
    //|ccc|xxxxx| |xxxxxxxx| |xxxxxxxx| |xxxxxxxx| |xxxxxxxx| |xxxxxxxx|
    // ^^^   5         8          8          8          8          8
    // 000 <-5->
    // 001 <------13------>
    // 010 <-----------21------------>
    // 011 <-----------------29----------------->
    // 100 <-----------------------37---------------------->
    // 101 <----------------------------45---------------------------->
    // 110 ... etc
     
    template<typename U>
    inline unsigned count_serial_unsigned(U u)
    {
    	//U must be unsigned 16, 32 or 64 bits
    	unsigned const shift_bits=serializable_type<U>::log2;
    	unsigned const bytes=serializable_type<U>::bytes;
    	//loose the log2(sizeof(U)) most significant bits
    	u<<=shift_bits;
    	//count bytes
    	unsigned count_bytes=bytes-1;
    	while (count_bytes && (u & U(0xFF)<<((bytes-1)*8))==0)
    	{
    		u<<=8;
    		--count_bytes;
    	}
    	return count_bytes+1;
    }
     
     
    template<typename IT, typename U>
    inline IT serialize_unsigned(IT it_out, U u)
    {
    	//IT is meant to be a byte string iterator
    	//U must be unsigned 16, 32 or 64 bits
    	unsigned const shift_bits=serializable_type<U>::log2;
    	unsigned const bits=serializable_type<U>::bits;
    	unsigned const bytes=serializable_type<U>::bytes;
    	//loose the log2(sizeof(U)) most significant bits
    	u<<=shift_bits;
    	//count bytes
    	unsigned count_bytes=bytes-1;
    	while (count_bytes && (u & U(0xFF)<<((bytes-1)*8))==0)
    	{
    		u<<=8;
    		--count_bytes;
    	}
    	//reconstruct shifted value, add count bytes in front
    	u=(U(count_bytes)<<(bits-shift_bits)) | (u>>shift_bits);
    	//serialize most significant byte first
    	u=byte_swap(u);
    	do
    	{
    		*it_out=(unsigned char)u;//explicit truncation
    		++it_out;
    		u>>=8;
    	}
    	while (count_bytes--);
    	return it_out;
    }
     
     
    template<typename IT, typename U>
    inline IT unserialize_unsigned(IT cit_in, U & ru)
    {
    	//IT is meant to be a byte string iterator
    	//U must be unsigned 16, 32 or 64 bits
    	unsigned const shift_bits=serializable_type<U>::log2;
    	U u=(unsigned char)*cit_in;
    	++cit_in;
    	unsigned count_bytes=unsigned(u>>(8-shift_bits));
    	u&=(0xFF>>shift_bits);
    	while (count_bytes)
    	{
    		u<<=8;
    		u|=(unsigned char)*cit_in;
    		++cit_in;
    		--count_bytes;
    	}
    	ru=u;
    	return cit_in;
    }
     
     
    template<typename IT, typename U>
    inline IT serialize_unsigned_inverted(IT it_out, U u)
    {
    	//IT is meant to be a byte string iterator
    	//U must be unsigned 16, 32 or 64 bits
    	unsigned const shift_bits=serializable_type<U>::log2;
    	unsigned const bits=serializable_type<U>::bits;
    	unsigned const bytes=serializable_type<U>::bytes;
    	//loose the log2(sizeof(U)) most significant bits
    	u<<=shift_bits;
    	//count bytes
    	unsigned count_bytes=bytes-1;
    	while (count_bytes && (u & U(0xFF)<<((bytes-1)*8))==0)
    	{
    		u<<=8;
    		--count_bytes;
    	}
    	//reconstruct shifted value, add count bytes in front
    	u=(U(count_bytes)<<(bits-shift_bits)) | (u>>shift_bits);
    	//serialize most significant byte first
    	u=byte_swap(u);
    	do
    	{
    		*it_out=(unsigned char)u ^ 0xFF;//explicit truncation, inversion
    		++it_out;
    		u>>=8;
    	}
    	while (count_bytes--);
    	return it_out;
    }
     
     
    template<typename IT, typename U>
    inline IT unserialize_unsigned_inverted(IT cit_in, U & ru)
    {
    	//IT is meant to be a byte string iterator
    	//U must be unsigned 16, 32 or 64 bits
    	unsigned const shift_bits=serializable_type<U>::log2;
    	U u=(unsigned char)*cit_in ^ 0xFF;//restore inversion
    	++cit_in;
    	unsigned count_bytes=unsigned(u>>(8-shift_bits));
    	u&=(0xFF>>shift_bits);
    	while (count_bytes)
    	{
    		u<<=8;
    		u|=(unsigned char)*cit_in ^ 0xFF;//restore inversion
    		++cit_in;
    		--count_bytes;
    	}
    	ru=u;
    	return cit_in;
    }
    Il y a un code analogue pour sérialiser des entiers signés et des chaines unicode.

    Ce code conserve la relation l'ordre des données sérialisées (ie si A<B alors serialized(A)<serialized(B) en utilisant memcmp())

Discussions similaires

  1. compression et decompression des fichiers
    Par ron lavezi dans le forum Visual C++
    Réponses: 2
    Dernier message: 05/03/2015, 10h05
  2. [Lex/Yacc] Aide traduction des structures de contrôle
    Par pelo68 dans le forum Générateurs de compilateur
    Réponses: 2
    Dernier message: 07/12/2010, 10h26
  3. [Stratégie] Type des structure de persistance
    Par calogerogigante dans le forum Général Java
    Réponses: 10
    Dernier message: 09/02/2006, 08h06
  4. Probleme avec des structures
    Par lenectar dans le forum C
    Réponses: 17
    Dernier message: 30/12/2005, 09h53
  5. Compresser et decompresser un ensemble de fichier
    Par Walm dans le forum C++Builder
    Réponses: 2
    Dernier message: 12/01/2004, 16h23

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