78
#include <iostream>

using namespace std;

int main()
{  
    char          c1 = 0xab;
    signed char   c2 = 0xcd;
    unsigned char c3 = 0xef;

    cout << hex;
    cout << c1 << endl;
    cout << c2 << endl;
    cout << c3 << endl;
}

I expected the output are as follows:

ab
cd
ef

Yet, I got nothing.

I guess this is because cout always treats 'char', 'signed char', and 'unsigned char' as characters rather than 8-bit integers. However, 'char', 'signed char', and 'unsigned char' are all integral types.

So my question is: How to output a character as an integer through cout?

PS: static_cast(...) is ugly and needs more work to trim extra bits.

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • afaik, casting is the most effective way... (e.g. `static_cast()`) – Nim Feb 01 '13 at 10:55
  • 1
    btw. the only reason you need to resort to "trimming" is that you are clearly not using the types correctly (the first two *clearly* overflows) and this is what you get as a result. If you always used the correct type, then the cast is simply, `static_cast(...)`... – Nim Feb 01 '13 at 11:10
  • 2
    There is also the option of `cout << +c1;` – PlasmaHH Feb 01 '13 at 11:23
  • @Nim where do you see any overflow? There's even no arithmetic going here, the values assigned are just `0xffffffab` and `0xffffffcd` on systems with 32 bit two's complement `int`s, and are then casted to smaller `char`s, which fit them perfectly due to the nature of two's complement representation. – Ruslan Jul 24 '15 at 07:27
  • @Ruslan there is no 0xffffffab and 0xffffffcd here, but 0xab and 0xcd are too big for signed char, maximum value for signed char is 0x7f. Yes bit representation allows you that, but it's platform dependent, what actually you get. Not all platforms are using compliment of two. – Swift - Friday Pie Sep 21 '19 at 06:53

6 Answers6

171
char a = 0xab;
cout << +a; // promotes a to a type printable as a number, regardless of type.

This works as long as the type provides a unary + operator with ordinary semantics. If you are defining a class that represents a number, to provide a unary + operator with canonical semantics, create an operator+() that simply returns *this either by value or by reference-to-const.

source: Parashift.com - How can I print a char as a number? How can I print a char* so the output shows the pointer's numeric value?

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
daniel
  • 1,868
  • 1
  • 12
  • 9
  • 2
    Working link: http://www.cs.technion.ac.il/users/yechiel/c++-faq/print-char-or-ptr-as-number.html – GetFree May 11 '17 at 08:58
  • 2
    This is rather obfuscated. A simple `static_cast` as in [sheu's answer](https://stackoverflow.com/a/14644745/1557062) clearly conveys the intend. – sigy Jun 29 '17 at 06:52
  • why is this the most upvoted answer. it is so much more obscure that a simple cast eg: (int) – deltanine Mar 21 '18 at 22:32
  • 5
    Yes, it is obscure, but is very useful in generic code. – Evg Aug 24 '18 at 07:01
  • @Evg `static_cast` is infinitely more useful in places like """generic code""" aka templates which already is unreadable enough without arbitrary abuse of features that not everyone knows about. It's irrelevant whether I know this or not myself, if most people who are going to read it are unlikely to, it does more harm than good. –  Dec 05 '19 at 16:03
  • `static_cast` will not work for template code. For code `cout << static_cast(val)`, what should `T` be if `val` is `float`, `int8_t`, `int`, `long long`? Using `+` solves all issues even though it's obscure a bit. – tstanisl Jan 07 '21 at 10:53
  • 3
    Came here for exactly this problem: properly emitting values from a templated numeric type. Ideally, there's be a more explicit operator, like `valueOf` or perhaps a stream modifier, but in the absense of these, the unary plus work across all numeric types. Regarding the trickiness of this syntax, this is precisely why languages include comments, and I strongly suggest this warrants a short comment. – Steve Hollasch Feb 02 '21 at 20:40
10

Cast them to an integer type, (and bitmask appropriately!) i.e.:

#include <iostream>

using namespace std;

int main()
{  
    char          c1 = 0xab;
    signed char   c2 = 0xcd;
    unsigned char c3 = 0xef;

    cout << hex;
    cout << (static_cast<int>(c1) & 0xFF) << endl;
    cout << (static_cast<int>(c2) & 0xFF) << endl;
    cout << (static_cast<unsigned int>(c3) & 0xFF) << endl;
}
sheu
  • 5,653
  • 17
  • 32
  • 2
    And the output of `c1` and `c2` is `ffffffab` and `ffffffcd`, which is _not_ what the OP expected. – Mr.C64 Feb 01 '13 at 10:58
  • However, 'char', 'signed char', and 'unsigned char' are all integral types. static_cast(...) is ugly and needs more work to trim extra bits. – xmllmx Feb 01 '13 at 11:09
  • @xmllmx: `ostream` also has overloads that print the `char` types as their character representations -- not what the poster wants, – sheu Feb 01 '13 at 11:12
7

Maybe this:

char c = 0xab;
std::cout << (int)c;

Hope it helps.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
Luka Pivk
  • 466
  • 2
  • 19
  • char is an unsigned integer. Casting it to int can show weird values. Better to cast to uint8_t. – RajV Dec 23 '22 at 14:38
  • Not really, `uint8_t` is alias. Its actual underlying type is `unsinged char` Also signage of `char` platform specific, hence the usage of types `unsinged char` and `signed char` – Gotiasits Jan 05 '23 at 11:23
2

Another way is to overload the << operator:

#include <iostream>

using namespace std;
typedef basic_ostream<char, char_traits<char>> basicOstream;

/*inline*/ basicOstream &operator<<(basicOstream &stream, char c) {
    return stream.operator<<(+c);
}
/*inline*/ basicOstream &operator<<(basicOstream &stream, signed char c) {
    return stream.operator<<(+c);
}
/*inline*/ basicOstream &operator<<(basicOstream &stream, unsigned char c) {
    return stream.operator<<(+c);
}

int main() {
    char          var1 = 10;
    signed char   var2 = 11;
    unsigned char var3 = 12;
    
    cout << var1 << endl;
    cout << var2 << endl;
    cout << var3 << endl;
    
    return 0;
}

which prints the following output:

10
11
12

Process finished with exit code 0

I think it's very neat and useful. hope it hepls!


And Also if you want it to print a hex value you can do like this:

basicOstream &operator<<(basicOstream &stream, char c) {
    return stream.operator<<(hex).operator<<(c);
} // and so on...
1

What about:

char c1 = 0xab;
std::cout << int{ c1 } << std::endl;

It's concise and safe, and produces the same machine code as other methods.

mt3d
  • 315
  • 2
  • 11
0

Another way to do it is with std::hex apart from casting (int):

std::cout << std::hex << (int)myVar << std::endl;

I hope it helps.

omotto
  • 1,721
  • 19
  • 20