paulo1205
(usa Ubuntu)
Enviado em 19/03/2016 - 19:31h
Eis uma das Infelicidades herdadas do C.
Nos nossos PCs,
uint8_t é um typedef (ou equivalente) com mais ou menos o seguinte aspecto:
typedef unsigned char uint8_t;
Em outras palavras, dá exatamente na mesma declarar uma variável qualquer como
uint8_t ou como
unsigned char . E as operações de entrada e saída formatada em streams tratam dados dos tipos
char ,
signed char e
unsigned char do mesmo modo, ou seja, como representando caracteres, e não inteiros de oito bits.
Uma das soluções já foi apresentada: uma conversão estática de tipo para inteiro de maior precisão na hora da impressão. Contudo, essa solução só resolve o problema na hora de imprimir, não de ler. E cabe mais uma ressalva: muita gente -- inclusive eu -- desaconselha o uso de conversão de tipos ao estilo de C; é melhor você fazer conversão ao estilo construtor de conversão de tipo (e.g. “
int(some_uint8_var) ”) ou conversão estática explícita (e.g. “
static_cast<int>(some_uint8_var) ”).
Outra abordagem é usar uma classe envelopadora de baixo custo (possivelmente custo zero, com um bom compilador) que tire dos seus bytes a característica original de representar caracteres.
class my_uint8_t {
// I/O operators
friend istream &operator >>(istream &, my_uint8_t &);
friend ostream &operator <<(ostream &, const my_uint8_t &);
private:
uint8_t value;
public:
// Template for type-conversion constructors
template <typename T=unsigned> my_uint8_t(const T &v=T()):
value(static_cast<uint8_t>(v))
{ }
// Type conversion to other types
// Note that implicit conversion is allowed only to unsigned int;
// direct conversion to other types (i.e. not going through conversion
// to unsigned int first) must be explicit. A good side-effect is that
// we don't need to write lots of binary operator functions (e.g. for
// arithmetic and logical operations).
operator unsigned() const { return value; }
template <typename T> explicit operator T() const { return T(value); }
// Unary operators
my_uint8_t operator +() { return *this; }
int operator -() { return -int(value); }
bool operator !() { return !value; }
my_uint8_t operator ~() { return ~value; }
my_uint8_t &operator ++() { ++value; return *this; }
my_uint8_t operator ++(int) { auto temp=value; ++value; return temp; }
my_uint8_t &operator --() { --value; return *this; }
my_uint8_t operator --(int) { auto temp=value; --value; return temp; }
// Assignment operators
template <typename T> my_uint8_t &operator *=(const T &other){
value*=other;
return *this;
}
template <typename T> my_uint8_t &operator /=(const T &other){
value/=other;
return *this;
}
template <typename T> my_uint8_t &operator %=(const T &other){
value%=other;
return *this;
}
template <typename T> my_uint8_t &operator +=(const T &other){
value+=other;
return *this;
}
template <typename T> my_uint8_t &operator -=(const T &other){
value-=other;
return *this;
}
template <typename T> my_uint8_t &operator &=(const T &other){
value&=other;
return *this;
}
template <typename T> my_uint8_t &operator |=(const T &other){
value|=other;
return *this;
}
template <typename T> my_uint8_t &operator ^=(const T &other){
value^=other;
return *this;
}
template <typename T> my_uint8_t &operator <<=(const T &other){
value<<=other;
return *this;
}
template <typename T> my_uint8_t &operator >>=(const T &other){
value>>=other;
return *this;
}
};
istream &operator >>(istream &is, my_uint8_t &var){
unsigned u;
is >> u;
var.value=u;
return is;
}
ostream &operator <<(ostream &os, const my_uint8_t &var){
return os << unsigned(var.value);
}