Displaying chars as ints without explicit cast
Asked Answered
C

2

4

Every time I send a char to the cout object, it displays in ASCII characters unless I cast it to an int.

Q: Is there a way to display the numerical value of a char without an explicit cast?

I read somewhere that doing too many casts in your code could lead to a loss of integrity (of your program). I am guessing that chars display in ASCII for a particular reason, but I'm not sure why.

I am essentially creating a game. I am using small numbers (unsigned chars) that I plan to display to the console. I may be paranoid, but I get this uneasy feeling whenever I spam static_cast<int> everywhere in my code.

Cymar answered 28/6, 2012 at 0:54 Comment(4)
Can't you just use int instead of unsigned char? You're not using chars it to save memory, aren't you?Hackberry
The words you have read, "loss of integrity," are probably not precise enough for their present use. It depends on what you use the casts for. Bad casts are used to avoid the need to design and maintain a proper set of types, but this is not what you are doing here. The effect of the stream-insertion operator << is well-defined and broadly understood. To convert char to int to feed it to a stream is standard technique. There is no threat to integrity here.Lock
@Hackberry Yea I am using unsigned chars to save memory. Should I not be doing that?Cymar
@Dasaru: if you've got several million, the memory savings add up. if you've got a few dozen, the extra code needed will swamp the data savnigs.Gupton
C
5

There is nothing wrong with type-casting, though, especially if you use static_cast to do it. That is what you should be using. It allows the compiler to validate the type-cast and make sure it is safe.

To change the behavior of the << operator, you would have to override the default << operator for char values, eg:

std::ostream& operator <<(std::ostream &os, char c)
{
    os << static_cast<int>(c);
    return os;
}

char c = ...;
std::cout << c;

You could create a custom type that takes a char as input and then implement the << operator for that type, eg:

struct CharToInt
{
    int val;
    CharToInt(char c) : val(static_cast<int>(c)) {}
};

std::ostream& operator <<(std::ostream &os, const CharToInt &c)
{
    os << c.val;
    return os;
}

char c = ...;
std::cout << CharToInt(c);

You could create a function that does something similar, then you don't have to override the << operator, eg:

int CharToInt(char c)
{
    return c;
}

char c = ...;
std::cout << CharToInt(c);
Cuda answered 28/6, 2012 at 1:7 Comment(2)
Replacing the default streaming operator is not generally a good idea... you might want to print numbers for now, but may want to print characters as characters somewhere later in your code. Separately, the correct return type for operator<< is std::ostream& (i.e. it should be a reference).Thomism
That's why I provided alternatives that are more explicit. And I updated my examples, thanks.Cuda
T
0

As things go, this is a reasonable use of casts, but yes it can be improved. The "loss of integrity" involved is simply that if one of the data types changes from char to say double the cast will continue to compile but probably not do what you want. You can create a helper function instead:

inline int to_int(char c) { return static_cast<int>(c); }

Unlike the static_cast, this will only kick in when the original type is char, so if you changed to something like double you'd get a compiler warning - effectively a reminder to review your code.

Thomism answered 28/6, 2012 at 1:1 Comment(7)
He has asked how to do it without CASTs. Although (and I haven't been doing a TON of C++ lately) I really like this. :-)Lecture
I think you can also do something like template <typename T, typename U> T implicit_conversion(const U &u) { return u; }. Use like std::cout << implicit_conversion<int>(c); (untested, I can't remember which order the template arguments should be in for the deduction to work). That works for all types without containing any casts, so the compiler gets the opportunity to warn you if your conversion is legal but suspect.Passive
@trumpetlicks: "doing too many casts in your code"... this is called factoring... doing something potentially ugly in one controlled place.Thomism
@Steve: in the above code you can omit the static_cast<int>() if you don't feel it's adding value as documentation and simply let the return promote the char to int....Thomism
@Tony: agreed, the idea of my function is that when "you change to something like double", you get a warning only if your compiler thinks that converting the new type to int warrants one. So for example you can change to short without updating the code, because the short -> int conversion is no more worrying than char -> int.Passive
Come to think of it, if I didn't want the static_cast and didn't want to write a template, I think I'd put the implicit conversion in the calling code rather than the function: int to_int(int i) { return i; }. Saves writing a bunch of overloads.Passive
@Steve Jessop: the aim seems very specifically to display the ASCII codes of characters - int isn't itself significant as short or long would work as well. On that basis, int to_ascii_num(char) might be a better name, but I don't see any reason to loosen the parameter type.Thomism

© 2022 - 2024 — McMap. All rights reserved.