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++Builder Discussion :

Conversion hexa avec nombre de byte variables [Langage/Algorithme]


Sujet :

C++Builder

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut Conversion hexa avec nombre de byte variables
    Bonjour,

    J'ai besoin d'une fonction qui me convertit une chaine représentant de l'hexa en un int.
    Je connais bien les fonctions de conversion classique StrToInt, StrToInt64, etc...
    Sauf que la valeur que je dois convertir a une taille qui varie de 1 à 8 byte et cela à son importance car si par exemple la taille est de 2, ma valeur héxa "E0C0" doit être convertit en -8000 et non en 57536.
    Par contre si la taille vaut 4, là oui je voudrai avoir la valeur 57536...
    Il me faudrait donc une fonction "StrTo" plus générique, qui convertisse en héxa mais à laquelle on puisse fournir la "taille" de la valeur en byte... Afin que les valeurs négatives soient converties correctement...
    J'espère que je suis claire, j'en suis pas très sûre !!!!
    merci pour votre aide !!

    Pascale38

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 464
    Points : 24 885
    Points
    24 885
    Par défaut
    IntToHex et StrToInt pour de la conversion numérique 32 Bits !

    HexToBin et BinToHex pour du Binaire Pur non signé

    Enfin, avec un petit peu de connaissance de l'architecture Little Endian du 686, la convertion par cast ou par affectation est très simple !

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function StrToIntSigned16(const S: string): Smallint;
    begin
      Result := Smallint(StrToInt(S)); // cast pour bien comprendre, mais je ne le crois pas obligatoire !
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    short __fastcall StrToIntSigned16(const AnsiString S)
    {
      return (short)StrToInt(S); // le cast n'est même pas obligatoire, l'affectation est brute !
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      ShowMessage("0xE0C0 : " + IntToStr(StrToIntSigned16("0xE0C0")));
      ShowMessage("$E0C0 : " + IntToStr(StrToIntSigned16("$E0C0")));
     
      short IntSigned16 = StrToInt("0xE0C0");
      ShowMessage("E0C0 Direct : " + IntToStr(IntSigned16));
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    merci pour ta réponse.

    Ce que je voudrais éviter c'est justement de devoir caster en "short" si la taille de la valeur à convertir est de 2, en int si elle est de 4 en int64 si elle est de 8, etc...
    Je voudrai savoir s'il n'est pas possible de faire ça de façon "générique".

    HexToBin ne m'intéresse pas vraiment car je veux une valeur décimale...
    A moins qu'il y ai un moyen simple ensuite de convertir ce binaire en décimal ??

    merci !
    Pascale38

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 464
    Points : 24 885
    Points
    24 885
    Par défaut
    Citation Envoyé par Pascale38 Voir le message
    Ce que je voudrais éviter c'est justement de devoir caster en "short" si la taille de la valeur à convertir est de 2, en int si elle est de 4 en int64 si elle est de 8, etc...
    Tu ne peux pas dépasser 8 pour des nombres entiers gérés nativement en C++, après il faut passer à des lib comme l'équivalent du BigInteger du C# 4.0

    Si tu reste à 2, 4 et 8, tu utilises du Int64 systématiquement !
    Tu vérifies la taille de la chaine Hexa pour déterminer quel est le bit de poids fort avec BTS, tu retire ce bit (16eme ou 32eme), et tu le remplace au 64eme bit (avec complément binaire), ainsi tu conserve le signe sans avoir besoin de caster !

    Ou autre méthode, en fonction de la longueur tu choisi le cast !

    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
    //---------------------------------------------------------------------------
    __int64 __fastcall StrToSignedInt(const AnsiString S)
    {
      int L = S.Length();
      if (L >= 3)
      {
        if (S[1] == '0')
        {
          if (S[2] == 'x')
            L=-2;
        }
        else
        {
          if (S[1] == '$')
            L--;
        }
     
        switch (L)
        {
          case 2: return (char)StrToInt(S);
          case 4: return (short)StrToInt(S);
          case 8: return StrToInt(S);
          case 16: return StrToInt64(S);
        }
      }
      throw EConvertError(Sysconst_SInvalidInteger, OpenArray<TVarRec>(S), 0);
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    oui caster selon la taille c'est bon j'ai depuis le début ça !!

    Par contre là :
    Tu vérifies la taille de la chaine Hexa pour déterminer quel est le bit de poids fort avec BTS, tu retire ce bit (16eme ou 32eme), et tu le remplace au 64eme bit, ainsi tu conserve le signe sans avoir besoin de caster !

    heu c'est trop fort pour moi
    Comment je fais ça ??
    et BTS c'est quoi ???
    Bon enfin si tu as le temps hein, parce que bon moi ce que je voulais c'est faire un truc "propre" quoi mais bon c'est pas grave !
    merci en tout cas !!
    Pascale38

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Heu en fait le fait de "caster" ne réponds qu'à moitié à mon problème, vu qu'en fait la taille peut être aussi 3 ou 5 ou 6 ou 7, et dans ces cas là je n'ai pas de type pour caster !!
    Donc retour à la case départ...
    Donc peux tu m'éclairer sur la méthode dont tu parles là :
    Tu vérifies la taille de la chaine Hexa pour déterminer quel est le bit de poids fort avec BTS, tu retire ce bit (16eme ou 32eme), et tu le remplace au 64eme bit (avec complément binaire), ainsi tu conserve le signe sans avoir besoin de caster !
    merci d'avance !
    Pascale38

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 464
    Points : 24 885
    Points
    24 885
    Par défaut
    La notion de "propre" est toute relative !
    utiliser le type de la bonne taille c'est LA méthode !
    La Longueur de la chaine source est déjà une bonne indication !
    Sinon, il faudrait utiliser le Log2 pour ne pas dépendre la longueur de la chaine mais de la longueur du nombre en octet

    Tiens, du très vilain ASM !
    Il y a surement mieux pour mettre les 1 du complément à 2 mais bon, ça devrait être bon

    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
    #pragma inline
    __int64 __fastcall BitSignReplace(int I /*EAX*/, short ByteCount /*EDX*/)
    {
      __int64 Result;
      bool b = false;
      asm
      {
        MOV ECX, EDX
        SHL ECX, 3
        DEC ECX
     
        IfNeg:
        BT EAX, ECX
        JNC EndIfNeg
        MOV b, 1;
        EndIfNeg:
     
        MOV I, EAX
      }
      if (b)
      {
        switch (ByteCount)
        {
          case 1: Result = 0xFFFFFFFFFFFFFF00i64 | I; break;
          case 2: Result = 0xFFFFFFFFFFFF0000i64 | I; break;
          case 4: Result = 0xFFFFFFFFFF000000i64 | I; break;
        }
      }
      else
        Result = I;
     
      return Result;
    }
     
     
    //---------------------------------------------------------------------------
    __int64 __fastcall StrToSignedInt(const AnsiString S)
    {
      __int64 Result = StrToInt64(S);
     
      int P = Log2(Result);
      if ((0 <= P) && (P < 8))
      {
        return BitSignReplace(Result, 1);
      }
      else if ((8 <= P) && (P < 16))
      {
        return BitSignReplace(Result, 2); 
      }
      else if ((16 <= P) && (P < 32))
      {
        return BitSignReplace(Result, 4); 
      }
      else
        return Result;
    }
    Cela reste limité au système normal 1, 2 et 4 pour short, smallint et integer

    En faisant le positionnement des Bits un par un (ouch)
    Ce qui radicalement le résultat, à toi de savoir quels sont les positions du Bit de Signe autre que 7, 15 et 31 !

    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
    #pragma inline
    __int64 __fastcall BitSignReplaceByBTS(int I /*EAX*/, int OldBitSign /*EDX*/)
    {
      __int64 Result;
      bool b = false;
      asm
      {
        BT EAX, EDX
        JNC EndIf
        MOV b, 1;
        EndIf:
     
        MOV I, EAX
      }
      if (b)
      {
        asm
        {
          MOV ECX, 31
          MOV EAX, I
     
          StartLoop:
          CMP ECX, OldBitSign
          JE EndLoop
     
          BTS EAX, ECX
          DEC ECX
          JMP StartLoop
          EndLoop:
     
          MOV I, EAX
        }
        Result = 0xFFFFFFFF00000000i64 | I;
      }
      else
        Result = I;
     
      return Result;
    }
     
    //---------------------------------------------------------------------------
    __int64 __fastcall StrToSignedIntByBTS(const AnsiString S)
    {
      __int64 Result = StrToInt64(S);
     
      int P = Log2(Result);
      if ((0 <= P) && (P < 32))
      {
        return BitSignReplaceByBTS(Result, P);
      }
      else
        return Result;
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    Là tu me parlerais chinois que ça me ferait le même effet
    Trop trop bas niveau pour moi.

    Par contre je crois que j'ai trouvé ce que je cherchais (à partir d'un tableau de BYTE).
    J'ai mis tout ça dans une fonction et voilà le résultat :
    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
     
    __int64 ByteToInt(BYTE * array, int size){
     
    	int shift = (size - 1) * 8;
    	long l=0;
     
    	for (int i=0; i<size; i++, shift -= 8) {
    		l += ((long) 0xFF & array[i]) << shift;
    	}
     
    	long hiOrderBit = ((long) array[0] & 0x80);
    	if (hiOrderBit == 0x80){
    		__int64 mask = ((__int64) -1 << (size * 8));
    		l = l | mask;
    	}
    	return l;
    }
    ça à l'air de fonctionner pas mal, et en tout cas de bien répondre à mon besoin !
    Qu'en penses tu ?

    Encore merci pour ton aide !!
    Pascale38

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 464
    Points : 24 885
    Points
    24 885
    Par défaut
    Effectivement, tu gères manuellement les octets en pensant qu'avec le LittleEndian l'ordre est inversé dans le tableau par rapport à ce que l'on écrirait en tant qu'humain !
    C'est très bien ta méthode est nettement plus propre, du coup tu utilises BinToHex pour obtenir ton Byte* ?

    Sinon, pour info, en modifiant StrToSignedIntByBTS, on obtient le même résultat !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //---------------------------------------------------------------------------
    __int64 __fastcall StrToSignedIntByBTS(const AnsiString S)
    {
      __int64 Result = StrToInt64(S);
     
      double P = Log2(Result);
      if ((0 <= P) && (P < 56))
      {
        return BitSignReplaceByBTS(Result, Ceil(P / 8) * 8 - 1);
      }
      else
        return Result;
    }
    On pouvait obtenir aussi l'équivalent en modifiant le switch
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    switch (ByteCount)
        {
          case 1: Result = 0xFFFFFFFFFFFFFF00i64 | I; break;
          case 2: Result = 0xFFFFFFFFFFFF0000i64 | I; break;
          case 3: Result = 0xFFFFFFFFFF000000i64 | I; break;
          case 4: Result = 0xFFFFFFFF00000000i64 | I; break;
          case 5: Result = 0xFFFFFF0000000000i64 | I; break;
          case 6: Result = 0xFFFF000000000000i64 | I; break;
          case 7: Result = 0xFF00000000000000i64 | I; break;
        }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Points : 79
    Points
    79
    Par défaut
    ma méthode faut pas exagérer, c'est de la récup hein, je n'en suis pas l'auteur !!! donc les félicitations à celui qui l'a écrite...

    ben du coup non je n'ai pas utilisé BinToHex vu qu'à la base je reçois directement les octets dans un char* ... Je l'avais convertit en String car plus lisible mais bon...

    En ce qui concerne ta méthode, le problème, c'est que je ne pense pas que mon client soit très content s'il voit de l'assembleur dans mon code...

    En tout cas merci beaucoup pour ton aide, et je mets le poste en résolu !

    Pascale38

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

Discussions similaires

  1. Somme d'une colonne (avec nombre de rangée variable)
    Par Berny77 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 13/05/2008, 23h30
  2. Formulaire avec nombre de champ variable
    Par david87 dans le forum IHM
    Réponses: 0
    Dernier message: 21/04/2008, 10h16
  3. Requete paramétrée avec nombre de champs variable
    Par Braillane dans le forum Accès aux données
    Réponses: 3
    Dernier message: 07/02/2008, 23h09
  4. Un script shell avec nombre d'argument variable
    Par lastrecrue dans le forum Linux
    Réponses: 1
    Dernier message: 28/05/2006, 11h35
  5. méthodes avec nombres d'arguments variable
    Par spynux dans le forum Langage
    Réponses: 2
    Dernier message: 26/05/2006, 13h51

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