[C++] problème char*

Résolu/Fermé
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 - 22 mai 2009 à 21:31
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 - 23 mai 2009 à 16:33
Bonjour,

Mon problème est surement pas très dur, mais je n'arrive pas à voir d'où il vient...

J'ai un nombre codé en binaire, et je le "découpe" en paquets de 1, 4, ou 8 pour avoir une chaine de caractères qui représente la notation binaire, hexadécimal ou en octet.

Avec 1 ou 4 ça marche mais avec 8, ma chaine revient avec strlen==0 !!!

Voici le code qui pose problème
template <int nbBit>
char* gdnombre<nbBit>::extraire(const short base=256) 
{
     short b=8;
     if (base==2)  b=1;
     if (base==16) b=4; 
            
     int n=(nbBit+1)/b;
     char * ch = new(char[n+1]);
     
     for (int i=n; i>=0; i--)
     {
        short s=recuperer(this,i,b); // entier compris entre 0 et 2^b-1
        
        if (b==8) ch[n-i]=(char) s; // renvoie rien : strlen==0
        else ch[n-i]=(s<=9) ? ('0'+s) : ('A'+s-10); // renvoie le bon résultat
     }  
     
     return ch;
}
A voir également:

6 réponses

mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
23 mai 2009 à 13:11
Pour comprendre le code que je t'ai codé il faut d'abord connaître les opérateurs du C sur les bits et la manière dont est stocké en mémoire un entier.

Manipuler des bits (sans mauvais jeu de mot) en C :

Les opérateurs s'appliquent sur des champs de bits faisant le même nombre de bit (éventuellement au travers d'un cast implicite) :
- x & y effectue un ET logique bit à bit de x et y
- x | y effectue un OU logique bit à bit de x et y
- ~x effectue un NON logique bit à bit sur x
- x << n décale le champ de bit x de n cran à gauche. Les bits qui "apparaissent" à droite valent 0. Par exemple 1 << 4 (ie 0000....01 << 4 en binaire revient à écrire 000....010000).
- x >> n fait la même chose, mais à droite

De la même façon que tu as +=, *=, -=, %=, /= pour les opérateurs de base, tu as les opérateurs |=, &=, <<= etc...

Au niveau du stockage d'un entier les bits de poids faible décrivent les puissances de 2 les plus faibles et les bits de poids forts les puissances de 2 les plus élevées. Ainsi 5 = 1*4 + 0*2 + 1*1 s'écrit en binaire 0....0101. Si l'entier est signé (int au lieu de unsigned), le bit de poids fort vaut 1 si le nombre est négatif et 0 sinon.

Les bools (sans mauvais jeu de mot)

Les bool font effectivement 1 octet (pour des histoires d'adressage et de performance j'imagine) mais si ta donnée est une valeur vrai/fausse, ton programme se doit d'être lisible et donc d'utiliser un bool malgré tout.

De plus tu t'en sors bien car un char fera toujours 1 octet mais a priori si le type wide-char n'existait pas il pourrait être amené à grossir (de la même façon que les int font 32 bits ou 64 bits selon ton architecture de machine). Bref, reste rigoureux au niveau des types.

Les std::ostream

Parmi les std::ostream tu as effectivement std::cout mais aussi std::cerr et surtout tout ce qui est std::ofstream et std::ostringstream, c'est-à-dire des flux vers des fichiers ou des buffers.

Bonne chance
1
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
23 mai 2009 à 01:42
Dans le cas particulier des bases qui sont une puissances de deux et sur un nombre entier, cette méthode est très peu efficace car le mémoire est déjà encodé en base 2 en mémoire.

Exemple :
#include <iostream>

void convert_2(std::ostream & out,unsigned x){
    unsigned i;
    for(i=0;i<8*sizeof(x);++i){
        out << (x & (1 << (8*sizeof(x) - i - 1)) ? 1 : 0);
    }
    out << std::endl;
}

int main(){
    int x = 27;
    convert_2(std::cout,x);
    return 0;
}

De la même façon tu peux facilement faire des fonctions très efficaces pour les bases 8 et 16. Attention pour les int, le bit de poids fort est le bit de signe.

Bonne chance
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
23 mai 2009 à 02:44
En fait je faisais ce calcul sur un type gdentier<nbBit> défini par bool T[nbBit+1]

Au départ je faisais comme ça parce que je pensais que bool était défini sur un bit (c'était écrit comme ça dans mon cours)
Mais comme sizeof(gdentier<n>)==n+1 ça veut dire que 1 bool=1 octet, donc autant prendre un char !!!
Du coup je vais recommencer (pas tout heureusement, c'est à ça que sert la conception objet)

Par contre j'ai des questions par rapport à ton code...
Dans les paramètres (std::ostream & out,unsigned x)
Que peut être out sinon std::cout ? Quel est le type de x ?

Et ensuite 1 << (8*sizeof(x) - i - 1) apparemment c'est un bool mais que signifie l'opérateur << ?
Et x & 1, x & 0 ça fait quoi ?

Désolé, j'ai une soif d'apprendre immense, mais mes cours ne suffisent plus ^^
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
23 mai 2009 à 12:30
Après une petite recherche je crois avoir compris le traitement des bits...
Mais je vais partir sur des bases plus simples avec bitset plutôt que bool
Comme ça je devrais pouvoir faire mes calculs bits à bits sans ces opérateurs de bits que je ne connais pas
#include <bitset>
using namespace std;

template <int nbBit=1>
class gdentier
{
   private:
            bitset<nbBit> N;
   public :
            inline bool get(const int i)
            {
                 return N[i];
            } 
            inline void set(const int i, const bool b)
            {
                 N[i]=b;     
            }
};
Par contre je me demande toujours ce qu'on peut utiliser comme ostream à part cout...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
23 mai 2009 à 15:37
Bon j'ai un peu avancé, mais je me retrouve bloqué quand même...

j'ai réussi à implémenter les fonctions de conversions en adaptant le code que tu m'as donné hier.
Mais je n'arrive pas à faire l'opérateur <<
// Dans mon .hpp

            inline void convert_2(std::ostream &); // OK
            inline void convert_16(std::ostream &); // OK
            inline void convert_256(std::ostream &); //OK
            
            friend std::ostream &operator<<(std::ostream &, const gdentier &);

[Warning] friend declaration `std::ostream& operator<<(std::ostream &, const gdentier<nbBit> &)' declares a non-template function
[Warning] (if this not way you intended, make sure the function template has already been declared and add <> after the function name here)-Wno-non-template-friend disables this warning

// Dans Mon .cpp

template <unsigned nbBit>
std::ostream &operator<<(std::ostream & out, const gdentier<nbBit> & g)
{
     if (out==std::cout) g.convert_16(out);
else if (out==std::cerr) g.convert_2(out);  // pour cerr on détaille
else g.convert_256(out); // en particulier pour les fichiers

     return out;
}

// Dans mon main()

    gdentier<8> a(72);
    
    cerr << a << endl; // 01001000
    cout << a << endl; // 4B
    
[Linker error] undefined reference to `operator<<(std::ostream &, gdentier<8u> const&)'
[Linker error] undefined reference to `operator<<(std::ostream &, gdentier<8u> const&)'
Id returned 1 exit status
PS. L'erreur revient quelque soit l'implémentation de l'opérateur, mais je ne sais pas si on peut choisir un flux comme je l'ai fait avec mes if(out==)

Si là encore tu pouvais m'aider... Merci !
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
23 mai 2009 à 16:33
Pour ton opérateur << vu qu'il est template, il doit être implémenté dans le .hpp
template <unsigned nbBit>
std::ostream & operator << (std::ostream & out,const gdentier<nbBit> & g){
  if     (out == std::cout) g.convert_16(out);
  else if(out == std::cerr) g.convert_2(out);  // pour cerr on détaille
  else g.convert_256(out); // en particulier pour les fichiers
 return out;
}

Personnellement, je trouverais mieux en terme de design que la manière dont g est écrit dépende d'un paramètre autre que le flux de sortie (par exemple un membre de la classe). En fait je ne pensais même pas que c'était possible tellement l'approche est peu commune :-).

En ce qui me concerne je ferais plutôt une méthode write qui prend en paramètre la base en paramètre et un opérateur << inline qui appelle cette méthode.

Pour plus d'informations sur les templates :
http://www.commentcamarche.net/faq/sujet 11194 les templates en c

Bonne chance
0