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 (int) <-> (char) et entier supérieur à 256, sur plusieurs char.


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut Conversion (int) <-> (char) et entier supérieur à 256, sur plusieurs char.
    Bonjour,
    J'ai la contrainte de devoir stocker des entiers dans un fichiers et je me retrouve avec des fichiers plutôt volumineux.
    Même si tout fonctionne correctement je me posais la question suivante :
    J'utilise parfois la correspondance (char)mon_entier pour me renvoyer le caractère ascii d'un entier (inférieur à 256), je me demandais si il était possible de stocker sur deux char un entier supérieur à 256 (pour réduire dans la foulée la taille de mon fichier).
    Exemple (char)mon_entier avec mon_entier variable int qui vaut 257 me renvoi un caractère, mais si je fait (int)(char)mon_entier me renvoi 1, ce qui est a priori logique vu que j'ai bouclé ma table ASCII non?
    J'aimerais une méthode pour un renvoi de mon entier sur deux chars et plus mais ma méthode/approche n'est clairement pas la bonne.
    Comment faire.?
    Merci

  2. #2
    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 : 50
    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 faire s'appelle sauver les données en binaire (tu sauves directement les différents bits représentant ton entier, et non pas la représentation en base 10 de ceux-ci)

    La FAQ présente une méthode, à base de reinterpret_cast, que je n'aime pas trop car vraiment non portable : https://cpp.developpez.com/faq/cpp/?...ans-un-fichier (mais la partie ouverture du fichier est bonne quand même !)

    Par exemple, pour sauver des entiers sur 16 bits, tu peux faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    auto lower = static_cast<unsigned char> (i);
    auto higher = static_cast<unsigned char> (i >> 8);
    stream << lower << higher; // Ou l'autre sens, comme tu veux
    Et pour relire, un truc à base de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    unsigned short result = higher;
    result << 8;
    result += lower;

  3. #3
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut
    Super et un grand merci à toi c'est exactement cela que je cherchais, du coup j'ai codé ces deux petites fonctions pratique pour moi :

    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
    string ul_to_str(unsigned long nombre)
    {
    string str(4, ' ');
    str[0] = static_cast<char>((nombre >> 24) & 0xFF);
    str[1] = static_cast<char>((nombre >> 16) & 0xFF);
    str[2] = static_cast<char>((nombre >> 8) & 0xFF);
    str[3] = static_cast<char>((nombre) & 0xFF);
    return str;
    }
     
    unsigned long str_to_ul(string str)
    {
    unsigned long result;
    result = static_cast<unsigned long>((str[0]) & 0xFF) << 24;
    result += static_cast<unsigned long>((str[1]) & 0xFF) << 16;
    result += static_cast<unsigned long>((str[2]) & 0xFF) << 8;
    result += static_cast<unsigned long>((str[3]) & 0xFF);
    return result;
    }
    Ça marche même si j'avoue ne pas trop comprendre le pourquoi du & 0xFF
    Je poste car sait on jamais c’est très probablement mal codé et peux être sujet à critique,
    du coup tu me dit que c'est pas terrible niveau portabilité, c'est à dire?
    J'aurais des problèmes si j'exporte ce code sous Linux?
    Merci en tout cas.

  4. #4
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut
    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
    #include <iostream>
    #include <bitset>
     
    using namespace std;
     
    int main()
    {
        	char i = 0xFF;	
            char j = 0x76;
    	char k = i & j;
     
    	cout << std::bitset<8>(i) << endl;
    	cout << std::bitset<8>(j) << endl;
    	cout << std::bitset<8>(k) << endl;
    	return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    11111111
    01110110
    01110110
    Le 0xFF ne sert à rien.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 170
    Points : 12 291
    Points
    12 291
    Par défaut
    Le 0xFF ne sert à rien.
    Bin si, pour éviter la propagation de signe avec les opération de shift.
    Mais comme d'habitude, avec les bons outils, tout est toujours plus simple.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Citation Envoyé par neokal Voir le message
    Super et un grand merci à toi c'est exactement cela que je cherchais, du coup j'ai codé ces deux petites fonctions pratique pour moi :
    Ça marche même si j'avoue ne pas trop comprendre le pourquoi du & 0xFF
    Je poste car sait on jamais c’est très probablement mal codé et peux être sujet à critique,
    du coup tu me dit que c'est pas terrible niveau portabilité, c'est à dire?
    J'aurais des problèmes si j'exporte ce code sous Linux?
    Merci en tout cas.
    Côté portabilité, pour ce genre de choses tu devrais utiliser les types de tailles fixe (genre uint32_t, uint64_t) plutôt que les types comme unsigned long, parce que si (sous Linux, par exemple) tu sérialises un unsigned long de 64 bits sur quatre octets, tu en perds la moitié!

    Ensuite, ce qu'il faut garder en mémoire, c'est que le résultat que tu mets dans une string n'est pas forcément une chaîne valide. Même si on décide que les problèmes de "chaînes de caractères C" (qui ne peuvent pas contenir d'octet nul) sont hors-sujet car on est en C++, il reste les problèmes d'encodage: Sous Linux, il est très courant que le système soit configuré pour utiliser des chaînes de caractères encodées en UTF-8, et dans ce cas beaucoup de combinaisons sont invalides! Par exemple, si tu sérialises 0x00FFFFFF, tu obtiens un 0xFF suivi d'un autre 0xFF, ce qui est invalide en UTF-8.
    Sans parler de tous les caractères non-imprimables, etc.

    Personnellement, je suis réticent à appeler string une suite de caractères contenant des données brutes comme celle-ci. Tu devrais plutôt utiliser un vecteur de unsigned char (std::vector<unsigned char>), où là il est évident que ce sont des données brutes que tu manipules.

    ...Ou bien, tu sérialises sous forme de texte plutôt que faire une sérialisation binaire. C'est ce que semble recommander le C++, vu que la bibliothèque standard offre des objets ne pouvant être sérialisés que sous forme de texte (notamment les générateurs de nombres aléatoires).

  7. #7
    Membre à l'essai
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mars 2017
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2017
    Messages : 20
    Points : 20
    Points
    20
    Par défaut Merci, et pour les floats ?!!!
    Ok, merci pour les précisions Médinoc.
    Même si c'est pour un usage très simple je m'en suis tenu à tes précisions et aucun problèmes pour la gestion des entiers en tout cas.
    Le résultat était vraiment parfait pour ce que je recherchais.
    Aujourd'hui par contre j'ai un soucis concernant le même ordre de problème sauf que cette fois je dois stocker des floats. J'ai regardé à droite à gauche sur le net et je dois avouer que mon niveau est loin d’être bon pour comprendre ce que j'arrive à trouver sur le sujet. J'imagine déjà que juste le fait de pouvoir signer ou déplacer la virgule du float déjà met pas mal le désordre dans le rangement du 'mot' binaire à proprement parler.
    Du coup si quelqu'un à une piste de réflexion je suis preneur.
    Merci par avance

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,
    Citation Envoyé par Médinoc Voir le message
    Personnellement, je suis réticent à appeler string une suite de caractères contenant des données brutes comme celle-ci.
    A mon sens, c'est même plutôt aberrant (ce qui va bien plus loin que la simple réticence) d'utiliser le terme string pour ce genre de chose...

    Personnellement, si je devais choisir un terme pour désigner un ensemble de ...byte destiné à représenter des valeurs numérique de plus de 8 bits, j'utiliserais sans doute le terme de ByteArray (tableau de bytes)

    C'est d'autant plus vrai que, depuis C++17, nous disposons de std::byte qui est spécifiquement destiné à représenter la notion de byte (un ensemble de bits pour lequel on se fout royalement de la signification qui y est donnée )
    Tu devrais plutôt utiliser un vecteur de unsigned char (std::vector<unsigned char>), où là il est évident que ce sont des données brutes que tu manipules.
    Voir, si tu disposes de C++17, un vecteur de std::byte

  9. #9
    Membre à l'essai Avatar de meynaf
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2018
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2018
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Bin si, pour éviter la propagation de signe avec les opération de shift.
    Pas dans cet exemple : le signe peut se propager tant qu'il veut, puisqu'il reste dans le poids fort - lequel sera éliminé lors du cast en char, c'est à dire en octet.
    De plus, la variable "nombre" est déclarée unsigned, donc y a même pas de signe à propager...

    Désolé de me mêler de ce qui ne me regarde pas


    Citation Envoyé par bacelar Voir le message
    Mais comme d'habitude, avec les bons outils, tout est toujours plus simple.
    Ça c'est bien vrai !

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Citation Envoyé par neokal Voir le message
    Aujourd'hui par contre j'ai un soucis concernant le même ordre de problème sauf que cette fois je dois stocker des floats. J'ai regardé à droite à gauche sur le net et je dois avouer que mon niveau est loin d’être bon pour comprendre ce que j'arrive à trouver sur le sujet. J'imagine déjà que juste le fait de pouvoir signer ou déplacer la virgule du float déjà met pas mal le désordre dans le rangement du 'mot' binaire à proprement parler.
    Pour les nombres à virgule flottante, c'est beaucoup plus compliqué parce qu'ils peuvent contenir n'importe quoi sous le capot: Le standard C++ n'oblige pas à ce qu'ils soient conformes à la norme IEEE 754.
    En conséquence, il n'existe pas de "types flottants de taille donnée" dans le standard. Ce qui en gros laisse deux solutions:
    1. Toujours sérialiser les flottants sous forme de texte. Mais attentions au problèmes de locale: il faut faire des manips que je n'ai pas en tête (les experts en C++ du forum doivent pouvoir t'aider mieux que moi) pour s'assurer que sur toutes les plate-formes le point soit employé comme séparateur décimal. Sans quoi, un programme sur un OS en français pourrait échouer à communiquer avec un programme sur un OS en anglais.
    2. La méthode "on s'en fout": Partir du principe que tous les float sont des flottants IEEE 754 sur 32 bits, tous les double sont des flottants IEEE 754 sur 64 bits, et les long double n'existent pas. Puis utiliser des union pour les convertir respectivement en int32_t et int64_t.


    Le coup de "déplacer la virgule" me fait penser à la méthode alternative consistant à ne pas sérialiser de flottants, selon le principe de la "virgule fixe": Par exemple, on suppose qu'on n'accepte que 4 chiffres après la virgule, et alors travaille sur une multiplication par 10000:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    std::int64_t ToFixedPoint(double d)
    {
    	if(std::fabs(d) > std::numeric_limits<std::int64_t>::max() / 10000)
    		throw std::out_of_range("Cette valeur double est trop grande pour être convertie en virgule fixe.");
    	return static_cast< std::int64_t >( d * 10000 );
    }
    double FromFixedPoint(std::int64_t i)
    {
    	return i / 10000.0;
    }

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

Discussions similaires

  1. Conversion int en char *
    Par Trunks dans le forum C
    Réponses: 6
    Dernier message: 18/03/2006, 16h44
  2. Réponses: 12
    Dernier message: 12/03/2006, 15h53
  3. conversion int---->char
    Par andurand dans le forum C++
    Réponses: 10
    Dernier message: 30/05/2005, 17h36
  4. Réponses: 2
    Dernier message: 01/07/2004, 11h36

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