Why do fixed-width integers print out chars instead of ints?
Asked Answered
S

2

5

Given the following code.

#include <cstdint>
#include <iostream>
#include <limits>

int main()
{
    int8_t x = 5;
    std::cout << x << '\n';

    int y = 5;
    std::cout << y;

    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.get();

    return 0;
}

My output is a three-leaf clover and 5. If fixed-width integers are integers, why are they outputting their number's ASCII character symbol?

Edit: just found out this behavior only happens for 8-bit fixed-width integers? Is this compiler behavior?

Shaylynn answered 25/5, 2015 at 23:18 Comment(1)
std::is_same<std::int8_t, signed char>::valueHamill
F
13

Well, they are integers in the sense that you can do 8 bit integer arithmetic with them.

But apparently on your system, int8_t is implemented as a typedef to signed char. This is completely legal since signed chars are also integers, but gives unexpected results since the operator<< for signed chars prints their character symbol and not their numeric value. Anything else would just be weird if someone tried to print an signed char.

If you want to see the numeric value of your int8_t, just cast to int before printing.

Feuillant answered 25/5, 2015 at 23:21 Comment(2)
thanks for the answer. That was a tricky thing they did with int8_t.Shaylynn
I wish opaque typedefs exists... :(Paule
F
3

The (optional) fixed-width types intN_t, and also various other types like uint_fast16_t, uintmax_t and intptr_t, are aliases for one of the built-in integral types. You don't know what the actual types they're aliasing are, only that they must meet the documented constraints.

In the case of "exactly 8 bits", the constraints don't leave much room, though, and the only integral types that can be 8 bits wide are the char types (recall there are three of them). So int8_t, if it exists, must be an alias for either char or signed char.

Unrelatedly, iostreams defines overloads for operator<< for the all character types which have the effect of writing the value directly to the output rather than formatting the integer as a decimal string (this is so that you can conveniently write std::cout << 'a'), and this overload is also used for int8_t -- overload resolution works on types, not on type names. (It is perhaps regrettable that there is an special ostream overload for signed char; it might have been nicer to only provide the overload for char and treat the other types like ordinary integers.) That's why you see the value printed as a character in your system's encoding.

If you want to print the value formatted as a string, just convert it to one of the wider integral types. For example, you can apply the standard promotions with the unary plus: int8_t x = 5; std::cout << +x;

Fluorometer answered 25/5, 2015 at 23:33 Comment(8)
Must they really be aliases for the "built-in" integral types?Rostrum
@MSalters: Yes. The relevant wording is in the C standard, from which this library component is imported. The term "signed integer type" is a term of art, defined in "Language/Concepts/Types".Fluorometer
@Kerrek SB I never heard of using +x to change a char to an integer in the output. I thought it was just a redundant unary operator which explicitly stated a value was positive?Shaylynn
@WanderingIdiot: The C++ type system is bewilderingly complex. Default promotions and arithmetic conversions are not to be taken lightly :-SFluorometer
@WanderingIdiot the arithmetic operators all promote any integral type narrower than int to int before operating.Towill
@MattMcNabb: Or unsigned int, depending on the weather.Fluorometer
@KerrekSB by "narrower" I meant being of fewer (value) bits . Promotion to unsigned int only happens if the signed type was the same width but lower rank.Towill
@MattMcNabb: I see, yes. But then your statement was incomplete, since integral types that are not narrower may also be promoted (e.g. signed char and short int may have the same width as int, but are still promoted).Fluorometer

© 2022 - 2024 — McMap. All rights reserved.