views:

4392

answers:

4

I want to work with unsigned 8-bit variables in C++. Either unsigned char or uint8_t do the trick as far as the arithmetic is concerned (which is expected, since AFAIK uint8_t is just an alias for unsigned char, or so the debugger presents it.

The problem is that if I print out the variables using ostream in C++ it treats it as char. If I have:

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

then the output is:

a is ^@; b is 377

instead of

a is 0; b is ff

I tried using uint8_t, but as I mentioned before, that's typedef'ed to unsigned char, so it does the same. How can I print my variables correctly?

Edit: I do this in many places throughout my code. Is there any way I can do this without casting to int each time I want to print?

+9  A: 

Use:

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

And if you want padding with leading zeros then:

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

As we are using C-style casts, why not go the whole hog with terminal C++ badness and use a macro!

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

you can then say

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

Edit: Having said that, MartinStettner's solution is much nicer!

anon
Can I convince you to eschew the evil C-style casts once and for all? http://stackoverflow.com/questions/527999/is-it-ok-to-use-c-style-cast-for-built-in-types/528009#528009
Konrad Rudolph
Not in this case - it's about the only place I think they are justified.
anon
I would do it the same, except to avoid the cast I would use cout << hex << int(a); It means the same thing as a cast, without the cast. :)
Brian Neal
A: 

This will also work:

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;
}
Naveen
But then he has to use casts if he actually wants them output as chars, which seems a little unnatural!
anon
+13  A: 

I would suggest using the following technique:

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

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

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

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

It's short to write, has the same efficiency as the original solution and it lets you choose to use the "original" character output. And it's type-safe (not using "evil" macros :-))

MartinStettner
As long as we're eschewing macros: in order to be more fully C++, shouldn't you write `(int)hs.c` as `static_cast<int>(hs.c)`? :P
Seth Johnson
There is a slight bug in your code.If you feed a negative character in the code the hex value becomes 4 bytes instead of 2.Switching to `unsigned char` fixes the problem.
witkamp
+3  A: 

I'd do it like MartinStettner but add an extra parameter for number of digits:

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

So you have two digits by default but can set four, eight, or whatever if you want to.

eg.

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

It may seem like overkill but as Bjarne said: "libraries should be easy to use, not easy to write".

Jimmy J