Question

Je veux travailler avec des variables non signés 8 bits en C ++. Soit ou unsigned char faire l'affaire uint8_t jusqu'à l'arithmétique concerne (ce qui est prévu, puisque AFAIK est juste un int alias pour <=>, ou si le débogueur présente.

Le problème est que si j'imprimer les variables à l'aide ostream en C ++, il le traite en tant que char. Si j'ai:

unsigned char a = 0;
unsigned char b = 0xff;
cout << "a is " << hex << a <<"; b is " << hex << b << endl;

alors la sortie est:

a is ^@; b is 377

au lieu de

a is 0; b is ff

J'ai essayé d'utiliser <=>, mais comme je l'ai mentionné auparavant, c'est typedef à <=>, donc il fait la même. Comment puis-je imprimer correctement mes variables?

Modifier Je le fais dans de nombreux endroits à travers mon code. Est-il possible que je peux le faire sans Castings à chaque fois que je <=> veux imprimer?

Était-ce utile?

La solution

Je suggère d'utiliser la technique suivante:

struct HexCharStruct
{
  unsigned char c;
  HexCharStruct(unsigned char _c) : c(_c) { }
};

inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
{
  return (o << std::hex << (int)hs.c);
}

inline HexCharStruct hex(unsigned char _c)
{
  return HexCharStruct(_c);
}

int main()
{
  char a = 131;
  std::cout << hex(a) << std::endl;
}

Il est court à écrire, a la même efficacité que la solution originale et il vous permet de choisir d'utiliser la sortie de caractère « original ». Et il est de type sécurisé (ne pas utiliser les macros "mal": -))

Autres conseils

Utilisation:

cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;

Et si vous voulez padding avec des zéros à gauche puis:

#include <iomanip>
...
cout << "a is " << setw(2) << setfill('0') << hex << (int) a ; 

Comme nous utilisons jette C style, pourquoi ne pas le porc entier avec le terminal C de la badness et utiliser une macro!

#define HEX( x )
   setw(2) << setfill('0') << hex << (int)( x )

vous pouvez alors dire

cout << "a is " << HEX( a );

Modifier Cela dit, la solution de MartinStettner est beaucoup plus agréable

Vous pouvez en savoir plus sur ce à http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ et http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ . Je signale que cela parce qu'il est devenu clair que l'auteur des articles ci-dessus n'a pas l'intention.

La technique la plus simple et la plus correcte à faire imprimer un char comme hex est

unsigned char a = 0;
unsigned char b = 0xff;
auto flags = cout.flags(); //I only include resetting the ioflags because so
                           //many answers on this page call functions where
                           //flags are changed and leave no way to  
                           //return them to the state they were in before 
                           //the function call
cout << "a is " << hex << +a <<"; b is " << +b << endl;
cout.flags(flags);

Les lecteurs digèrent la version de la façon dont cela fonctionne est que l'opérateur unaire + force une conversion pas de type op à un int avec le signedness correct. Ainsi, un unsigned char convertit en entier non signé, un signed char convertit en int et char convertit soit signé unsigned int ou int selon que char ou non signé sur votre plate-forme (il se présente comme un choc pour beaucoup que l'omble est spécial et non spécifié comme signé ou non signé).

Le seul point négatif de cette technique est qu'il ne peut pas être évident ce qui se passe à quelqu'un qui ne connaît pas avec elle. Cependant, je pense qu'il est préférable d'utiliser la technique qui est correcte et enseigner aux autres à ce sujet plutôt que de faire quelque chose qui est incorrect, mais plus immédiatement clair.

Eh bien, cela fonctionne pour moi:

std::cout << std::hex << (0xFF & a) << std::endl;

Si vous venez jeté comme l'a suggéré qu'il (int) pourrait ajouter 1s à gauche si le bit a le plus significatif est 1. Donc, ce qui en fait binaire et le fonctionnement garantit la sortie aura les bits gauche remplis par des 0 et aussi le convertit en unsigned int forcer cout à imprimer comme hex.

J'espère que cette aide.

Hm, il semble que je réinventé la roue hier ... Mais bon, au moins il est une roue générique cette fois-ci :) s sont imprimés char avec deux chiffres hexadécimaux, avec 4 s short chiffres hexadécimaux et ainsi de suite.

template<typename T>
struct hex_t
{
    T x;
};

template<typename T>
hex_t<T> hex(T x)
{
    hex_t<T> h = {x};
    return h;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, hex_t<T> h)
{
    char buffer[2 * sizeof(T)];
    for (auto i = sizeof buffer; i--; )
    {
        buffer[i] = "0123456789ABCDEF"[h.x & 15];
        h.x >>= 4;
    }
    os.write(buffer, sizeof buffer);
    return os;
}

Je ferais comme MartinStettner mais ajoute un paramètre supplémentaire pour le nombre de chiffres:

inline HexStruct hex(long n, int w=2)
{
  return HexStruct(n, w);
}
// Rest of implementation is left as an exercise for the reader

Vous avez donc deux chiffres par défaut mais peut mettre quatre, huit, ou quoi que si vous voulez.

par exemple.

int main()
{
  short a = 3142;
  std:cout << hex(a,4) << std::endl;
}

Il peut sembler exagéré, mais comme Bjarne a dit:. « Les bibliothèques doivent être faciles à utiliser, pas facile d'écrire »

Je pense que TrungTN et la réponse de Anon est correct, mais la manière de MartinStettner de mettre en œuvre la fonction hex () n'est pas vraiment simple, et trop hexagonale sombre, considérant << (int) MyChar est déjà une solution de contournement.

voici ma solution pour faire "<<" opérateur plus facile:

#include <sstream>
#include <iomanip>

string uchar2hex(unsigned char inchar)
{
  ostringstream oss (ostringstream::out);
  oss << setw(2) << setfill('0') << hex << (int)(inchar);
  return oss.str();
}

int main()
{
  unsigned char a = 131;
  std::cout << uchar2hex(a) << std::endl;
}

Il est tout simplement pas digne mettre en œuvre un opérateur de flux: -)

Je suggère:

std::cout << setbase(16) << 32;

Tiré de: http://www.cprogramming.com/tutorial/iomanip.html

Vous pouvez essayer le code suivant:

unsigned char a = 0;
unsigned char b = 0xff;
cout << hex << "a is " << int(a) << "; b is " << int(b) << endl;
cout << hex
     <<   "a is " << setfill('0') << setw(2) << int(a)
     << "; b is " << setfill('0') << setw(2) << int(b)
     << endl;
cout << hex << uppercase
     <<   "a is " << setfill('0') << setw(2) << int(a)
     << "; b is " << setfill('0') << setw(2) << int(b)
     << endl;

Sortie:

a is 0; b is ff

a is 00; b is ff

a is 00; b is FF

J'utilise ce qui suit sur win32 / linux (32/64 bit):

#include <iostream>
#include <iomanip>

template <typename T>
std::string HexToString(T uval)
{
    std::stringstream ss;
    ss << "0x" << std::setw(sizeof(uval) * 2) << std::setfill('0') << std::hex << +uval;
    return ss.str();
}

Je voudrais poster ma version re-re-inventer basé sur @ FredOverflow de. J'ai fait les modifications suivantes.

fix:

  • Rhs de devrait être d'operator<< type de référence const. Dans @ code de FredOverflow, sortie change h.x >>= 4 h, ce qui est étonnamment pas compatible avec la bibliothèque standard, et le type est requared à T être copie constructible.
  • Supposons que est un multiple CHAR_BITS de 4 @ code de FredOverflow est de 8 assume char bits, ce qui est pas toujours vrai, dans certaines implémentations sur DSPs, en particulier, il est rare que 16 est std::uppercase -bits, 24 bits, 32 bits, etc.

améliorer:

  • Supporte tous les autres manipulateurs de la bibliothèque standard disponibles pour les types intégrés, par exemple _print_byte. Parce que le format de sortie est utilisé dans hex_sep, Manipulateurs de la bibliothèque standard sont encore disponibles.
  • Ajoutez à imprimer octets Sep séparés (notez que dans C / C ++ un « octet » est, par définition, une unité de stockage avec la taille de _Hex<T, false>). Ajout d'un paramètre de modèle et instancier _Hex<T, true> et hex dans size et Size respectivement _print_byte<true>.
  • Évitez météorisation code binaire. Fonction est extraite hors _print_byte<false> de sep, avec un paramètre de fonction if(sep), pour éviter instanciation pour différentes if.

En savoir plus sur météorisation code binaire:

Comme mentionné dans l'amélioration 3, peu importe largement et std::conditional est utilisé inline, seulement deux copies de (presque) fonction dupliquée sort en code binaire: et de ad be ef DEADBEEF <=>. Et vous pourriez réaliser que cette duplication peut également être éliminé en utilisant exactement la même approche: ajouter un paramètre de fonction <=>. Oui, mais si cela, un moteur d'exécution est nécessaire <=>. Je veux un utilitaire bibliothèque commune qui peut être largement utilisé dans le programme, donc je compromis sur la duplication plutôt que les frais généraux d'exécution. J'atteint cet objectif en utilisant la compilation <=>:. C 11 ++ <=>, les frais généraux d'appel de fonction peut espérer être optimisé par une distance <=>

hex_print.h:

namespace Hex
{
typedef unsigned char Byte;

template <typename T, bool Sep> struct _Hex
{
    _Hex(const T& t) : val(t)
    {}
    const T& val;
};

template <typename T, bool Sep>
std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h);
}

template <typename T>  Hex::_Hex<T, false> hex(const T& x)
{ return Hex::_Hex<T, false>(x); }

template <typename T>  Hex::_Hex<T, true> hex_sep(const T& x)
{ return Hex::_Hex<T, true>(x); }

#include "misc.tcc"

hex_print.tcc:

namespace Hex
{

struct Put_space {
    static inline void run(std::ostream& os) { os << ' '; }
};
struct No_op {
    static inline void run(std::ostream& os) {}
};

#if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here
#error "hex print utility need CHAR_BIT to be a multiple of 4"
#endif
static const size_t width = CHAR_BIT >> 2;

template <bool Sep>
std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size)
{
    using namespace std;

    auto pbyte = reinterpret_cast<const Byte*>(ptr);

    os << hex << setfill('0');
    for (int i = size; --i >= 0; )
    {
        os << setw(width) << static_cast<short>(pbyte[i]);
        conditional<Sep, Put_space, No_op>::type::run(os);
    }
    return os << setfill(' ') << dec;
}

template <typename T, bool Sep>
inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h)
{
    return _print_byte<Sep>(os, &h.val, sizeof(T));
}

}

test:

struct { int x; } output = {0xdeadbeef};
cout << hex_sep(output) << std::uppercase << hex(output) << endl;

sortie:

<=>

Je sais que c'est une vieille question, mais est aussi un résultat Google haut dans la recherche d'une solution à un problème très similaire je, qui est le désir de mettre en œuvre entier arbitraire à des conversions de chaîne hexagonale dans une classe de modèle. Mon objectif final était en fait un modèle de sous-classe qui permettrait Gtk::Entry éditer différentes largeurs entières en hexadécimal, mais qui est à côté du point.

combine l'astuce unaire avec operator+ de std::make_unsigned pour empêcher le <type_traits> problème de signe d'allongement négatif ou int8_t valeurs qui se produit signed char dans cette réponse

Quoi qu'il en soit, je crois que cela est plus succinct que toute autre solution générique. Il devrait fonctionner pour tout signé ou types d'entiers non signés, et génère une erreur de compilation si vous essayez d'instancier la fonction avec tous les types non entiers.

template < 
  typename T,
  typename = typename std::enable_if<std::is_integral<T>::value, T>::type
>
std::string toHexString(const T v)
{ 
  std::ostringstream oss;
  oss << std::hex << +((typename std::make_unsigned<T>::type)v);
  return oss.str();
}

Certains Exemple d'utilisation:

int main(int argc, char**argv)
{
  int16_t val;
  // Prints 'ff' instead of "ffffffff". Unlike the other answer using the '+'
  // operator to extend sizeof(char) int types to int/unsigned int
  std::cout << toHexString(int8_t(-1)) << std::endl;

  // Works with any integer type
  std::cout << toHexString(int16_t(0xCAFE)) << std::endl;

  // You can use setw and setfill with strings too -OR- 
  // the toHexString could easily have parameters added to do that.
  std::cout << std::setw(8) << std::setfill('0') << 
    toHexString(int(100)) << std::endl;
  return 0;
}

Mise à jour: Vous pouvez également, si vous ne voulez pas l'idée du ostringstream utilisé, vous pouvez combiner les modèlet tour opérateur unaire avec la solution struct-de réponse acceptée pour ce qui suit . Notez que ici, j'ai modifié le modèle en supprimant le contrôle des types entiers. L'utilisation peut être assez make_unsigned pour les garanties de sécurité de type compilation.

template <typename T>
struct HexValue 
{
  T value;
  HexValue(T _v) : value(_v) { }
};

template <typename T>
inline std::ostream& operator<<(std::ostream& o, const HexValue<T>& hs)
{
  return o << std::hex << +((typename std::make_unsigned<T>::type) hs.value);
}

template <typename T>
const HexValue<T> toHex(const T val)
{
  return HexValue<T>(val);
}

// Usage:
std::cout << toHex(int8_t(-1)) << std::endl;

Cela permettra également de travailler:

std::ostream& operator<< (std::ostream& o, unsigned char c)
{
    return o<<(int)c;
}

int main()
{
    unsigned char a = 06;
    unsigned char b = 0xff;
    std::cout << "a is " << std::hex << a <<"; b is " << std::hex << b << std::endl;
    return 0;
}

Je l'ai utilisé de cette façon.

    char strInput[] = "yourchardata";
char chHex[2] = "";

int nLength = strlen(strInput);
char* chResut = new char[(nLength*2) + 1];
memset(chResut, 0, (nLength*2) + 1);



for (int i = 0; i < nLength; i++)
{
    sprintf(chHex, "%02X", strInput[i]& 0x00FF);    
    memcpy(&(chResut[i*2]), chHex, 2);
}

printf("\n%s",chResut);
delete chResut;
chResut = NULL;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top