Pergunta

Eu quero trabalhar com variáveis ??de 8 bits não assinados em C ++. Ou unsigned char ou uint8_t fazer o truque tão longe como a aritmética está em causa (que é esperado, pois AFAIK uint8_t é apenas um alias para unsigned char, ou assim os presentes depurador-lo.

O problema é que se eu imprimir as variáveis ??usando ostream em C ++ trata-lo como char. Se eu tenho:

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

então a saída é:

a is ^@; b is 377

em vez de

a is 0; b is ff

Eu tentei usar uint8_t, mas como eu mencionei antes, que é typedef'ed para unsigned char, por isso faz o mesmo. Como posso imprimir minhas variáveis ??corretamente?

Editar: Eu faço isso em muitos lugares em todo o meu código. Existe alguma maneira eu posso fazer isso sem lançando a int cada vez que eu quiser imprimir?

Foi útil?

Solução

Gostaria de sugerir usando a seguinte técnica:

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;
}

É curto para escrever, tem a mesma eficiência que a solução original e permite que você optar por usar a saída de caráter "original". E é tipo seguro (não usar "mal" macros: -))

Outras dicas

Use:

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

E se você quiser preenchimento com zeros à esquerda, em seguida:

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

Como nós estamos usando moldes de estilo C, por que não ir o porco inteiro com a maldade do terminal C ++ e usar uma macro!

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

Você pode, então, dizer

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

Editar: Dito isto, a solução da MartinStettner é muito mais agradável

Você pode ler mais sobre isso em http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ e http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ . Eu só estou postando isso porque se tornou claro que o autor dos artigos acima não pretende.

A técnica mais simples e correta de fazer imprimir um char como hex é

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);

Os Readers Digest versão de como isso funciona é que o operador forças + unárias de nenhum tipo op conversão para um int com o signedness correta. Assim, um sem assinatura convertidos char para int não assinado, uma assinados convertidos char para int e um convertidos char para qualquer int sem sinal ou int dependendo se char é assinado ou sem assinatura e em sua plataforma (que vem como um choque para muitos que char é especial e não especificado como sinal ou sem sinal).

O único aspecto negativo desta técnica é que ela não pode ser óbvio o que está acontecendo a um alguém que não está familiarizado com ele. No entanto, penso que é melhor usar a técnica que é corrigir outros e ensinar sobre o assunto, em vez de fazer algo que é incorreto, mas mais imediatamente clara.

Bem, isso funciona para mim:

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

Se você acabou de lançar (int) como sugerido que poderia adicionar 1s para a esquerda de a se o bit mais significativo é 1. Então, tornando este binário operação AND garante a saída terá os bits esquerda preenchidas por 0s e também converte para sem assinatura int forçando cout imprimi-lo como hex.

Espero que isso ajude.

Hm, parece que eu re-inventou a roda ontem ... Mas hey, pelo menos é uma roda genérico desta vez :) chars são impressos com dois dígitos hexadecimais, shorts com 4 dígitos hexadecimais e assim por diante.

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;
}

Eu faria isso como MartinStettner mas adicionar um parâmetro adicional para o número de dígitos:

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

Então você tem dois dígitos por padrão, mas pode definir quatro, oito, ou qualquer outra coisa, se você quiser.

por exemplo.

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

Pode parecer um exagero, mas como disse Bjarne:. "Bibliotecas deve ser fácil de usar, não é fácil de escrever"

Eu acho que a resposta de TrungTN e logo é bom, mas forma de implementar o hex () função não é realmente simples, e muito escuro, considerando hex do MartinStettner << (int) mychar já é uma solução alternativa.

aqui é a minha solução para fazer "<<" operador mais fácil:

#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;
}

Não é apenas digno implementação de um operador de fluxo: -)

Gostaria de sugerir:

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

Retirado de: http://www.cprogramming.com/tutorial/iomanip.html

Você pode tentar o seguinte código:

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;

Output:

a is 0; b is ff

a is 00; b is ff

a is 00; b is FF

Eu uso o seguinte em 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();
}

Eu gostaria de postar minha versão-re-re inventar baseado em @ FredOverflow de. Eu fiz as seguintes modificações.

CORRECÇÃO:

  • Rhs de operator<< deve ser do tipo de referência const. Em @ código de FredOverflow, h.x >>= 4 muda h saída, que é surpreendentemente não é compatível com biblioteca padrão e tipo T é requared ser copy-construível.
  • assumir apenas CHAR_BITS é um múltiplo de 4. @ código de FredOverflow assume char é de 8-bits, o que nem sempre é verdade, em algumas implementações em DSPs, particularmente, não é incomum que char é de 16 bits, 24 bits , 32-bits, etc.

melhorar:

  • Suporte todos os outros manipuladores da biblioteca padrão disponíveis para tipos integrais, por exemplo, std::uppercase. Por causa do formato de saída é usado em _print_byte, manipuladores da biblioteca padrão ainda estão disponíveis.
  • Adicione hex_sep para imprimir bytes separados (nota que em C / C ++ um 'byte' é, por definição, uma unidade de armazenamento com o tamanho de char). Adicionar um Sep parâmetro do modelo e _Hex<T, false> instanciar e _Hex<T, true> em hex e hex_sep respectivamente.
  • Evite binário bloat código. _print_byte função é extraído da operator<<, com um função de parâmetro size, para evitar instanciação para Size diferente.

Mais sobre bloat código binário:

Conforme mencionado na melhoria de 3, não importa quão hex extensivamente e hex_sep é usado, apenas duas cópias de (quase) função duplicada vai saídas em código binário: _print_byte<true> e _print_byte<false>. E você pode percebeu que essa duplicação também pode ser eliminado usando exatamente a mesma abordagem: adicionar um sep parâmetro de função. Sim, mas se fazer isso, é necessário um if(sep) tempo de execução. Quero uma utilidade biblioteca comum que pode ser utilizada extensivamente no programa, assim eu comprometida na duplicação em vez de sobrecarga de tempo de execução. Eu consegui-lo utilizando if de tempo de compilação:. C ++ 11 std::conditional, a sobrecarga de chamada de função pode ser optimizada esperançosamente distância por inline

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));
}

}

teste:

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

saída:

de ad be ef DEADBEEF

Sei que esta é uma questão antiga, mas a sua também um top resultado Google na busca de uma solução para um problema muito semelhante que eu tenho, que é o desejo de implementar inteiro arbitrário para conversões de cadeia hex dentro de uma classe de modelo. Meu objetivo final era realmente modelo de um Gtk::Entry subclasse que permitiria a edição de várias larguras inteiros em hexadecimal, mas isso não vem ao caso.

Isto combina o truque operator+ unário com std::make_unsigned de <type_traits> para evitar o problema de valores int8_t ou signed char negativos-estendendo sinal que ocorre em este responder

De qualquer forma, acredito que este é mais sucinto do que qualquer outra solução genérica. Ele deve funcionar para qualquer assinado ou tipos inteiros não assinados, e lança um erro de tempo de compilação se você tentar instanciar a função com quaisquer tipos não inteiros.

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();
}

Alguns exemplo de uso:

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;
}

Update: Como alternativa, se você não gosta da idéia do ostringstream sendo usado, você pode combinar a modelagem e truque operador unário com solução baseada em struct a resposta é aceita para o seguinte. Note-se que aqui, eu modificado o modelo, removendo a verificação de tipos inteiros. O uso make_unsigned pode ser suficiente para garantias de segurança de tipo de tempo de compilação.

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;

Esta será também trabalho:

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;
}

Eu tenho usado desta forma.

    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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top