6 comments on “Tippet: Printing numeric values for chars (and (u)int8_t)

  1. I did know back then about the + trick, I recall learning it from the ##c++ channel, but anyway I’ve provided this answer here, at a duplicate I believe:


    Implementation could make use of the + trick instead of being written like that. The point I’m interested in your opinion is what you think about the client code, instead of using + before every char, if there’re many, I’ve used that ADL technic, what you think?

    • I’m not sure that’s a very useful pattern. It seems excessive when just a ‘+’ where you need it will do. And once you’ve turned it on, you can’t turn it off except by leaving the scope. And it could cause surprising changes of behaviour later in a function. It also makes the intention less clear – if I see a char being printed I have to go back and search for the using declaration to know whether it’s being printed as a letter or a number, but seeing the ‘+’ right at the point of writing is clear and obvious.

  2. Very instructive article.
    I like description of integral promotion as well as the unary + operator tip.
    I learned a lot.

    I didn’t understoot in this example why you say that tu is unsigned int:
    signed char cs = 32;
    unsigned char cu = 32;
    char c = 32;

    auto ts = -cs;
    auto tu = -cu;
    auto t = -c;

    So I checked:
    int main()
    // Reference names
    cout << "typeid(char).name(): " << typeid(char).name() << '\n';
    cout << "typeid(unsigned int).name(): " << typeid(unsigned int).name() << '\n';
    cout << "typeid(int).name(): " << typeid(int).name() << '\n';
    cout << '\n';

    unsigned char cu = 32;
    auto tu = -cu;

    cout << "cu:" << +cu << " – is of type " << typeid(cu).name()
    << " and size " << sizeof(cu) << '\n';
    cout << "tu:" << tu << " – is of type " << typeid(tu).name()
    << " and size " << sizeof(tu) << '\n';

    And in gcc 4.8.2 (as in mingw32) I get:
    typeid(char).name(): c
    typeid(unsigned int).name(): j
    typeid(int).name(): i

    cu:32 – is of type h and size 1
    tu:-32 – is of type i and size 4

    So it seems that tu is int not unsigned int in this case.

    As I understand for your great explanation, tu will be unsigned if char and int were of the same size in that implementation. In the usual case of char smaller than int, unsigned char should be prometed to int, if I understand correctly.

    Thanks again for the article.

    • Yeah, that was very sloppy writing on my part. Originally I did it with just operator+, then I thought it might not be clear because it has no observable effect (other than the changing of the type), so I changed it to use operator- first. But that, of course, means it doesn’t quite work right, so I added a little note about ignoring the signed range issue. Which made it all an unclear, incorrect muddle.

      I’ll stick in an update pointing out the mistake. Thanks for noticing!

      Incidentally, if you want to identify a type, there’s a really easy and foolproof way to do it that avoids all that typeid dancing. I’ll be writing a tippet about it in the near future, but here’s a sneak peek as thanks for spotting the error.

      The trick is to declare a template class… but don’t define it (apologies for WordPress mangling the code, I’m still working on fixing that, but I hope you get the gist):

      template &lt;typename T&gt; struct type_identifier;

      Then to identify a type, you just use the class, like this:

      unsigned char c;
      type_identifier&lt;decltype(c)&gt; id1;
      type_identifier&lt;decltype(-c)&gt; id2;

      These will trigger errors because the template class is undefined… but the error message will helpfully include the exact, correct, human-readable type.

      • Thanks for the trick :-)

        I remember a similar technique in a recent Scot Meyers talk.
        He used it to see which types type deduction was producing in diferent contexts.

        By the way, I’ve discovered this blog because two articles were highlighted today in isocpp.org and I’ve to say I’ve read most of it’s articles and enjoyed all of them.
        Thanks again.

      • David’s objection applies to the variable t as well, doesn’t it? Plain char being unsigned is necessary but not sufficient for t to become an unsigned int: char and int also need to be of equal size. I don’t have a machine where that’s the case, but the other condition is easily tested with GCC’s -f{,un}signed-char. Both flags result in (signed) int for me.

Leave a Reply

Your email address will not be published. Required fields are marked *