c++11inputprintfiostreamcstdint

C++ 11 int8_t buggy input/output


This is a snipped of code from my program. I am using the int8_t data type, and I'm having some problems with input/output. Apparently, using int8_t in the program requires the -std=c++11 flag to be set for the g++ compiler. I did that, but there are runtime errors. Here's my code:

#include <iostream>
#include <cstdint>
using std::cout;
using std::cin;
using std::endl;
int main() {
  int8_t number;

  cout << "Enter a number [1-100]: ";
  cin >> number;
  cout << "You entered: " << number << endl;
  cout << number << " / 10 = " << (number / 10) << endl;

  return 0;
}

Here is the output of the program:

 $ ./a.out
Enter a number [1-100]: 95
You entered: 9
9 / 10 = 5

The $ is the shell prompt. Anyway, it seems that only the first digit is read from the input stream. Even so, the integer division 9 / 10 should return 0, not 5. This program is intended to do 95 / 10 and return a result of 9. Theoretically, this program should work, but apparently, even the division operator is buggy. I should make a note that using int instead of int8_t causes the program to work as intended. I suspect that in this case someone would just tell me to use the int data type and deal with it. But we are software engineers! I would like to know if the int8_t data type is inherently flawed. Why it can't accept proper user input, but also breaks the division operator?! Any programming language worth using must be free of such imperfections. And I think that C++ is popular enough that eventually someone realized that int8_t is flawed in some sense. That is something I need to know the intricacies of.


Solution

  • First, the smallest type in C++ is char, and on most systems the last couple of decades that's equal to an 8-bit byte. So the type int8_t is usually an alias for signed char.

    Second, when reading a char (signed or unsigned) from a stream with the >> operator, it reads a character. It doesn't matter if an alias type (like int8_t) is used, it's still a char type and will be read as a character.

    So the result is that you read a single character, and the encoded value of that character is stored in your variable number. With ASCII encoding (the most common character encoding these days) the variable number will store the integer value 57 (ASCII for the character '9') which divided by 10 is equal to the integer 5.

    If you want to read a small integer, use int for the type. If you want to store it in a byte (using int8_t) you have to either use temporary int variables, or cast the variable to an int. This casting have to be done for the printing as well (since otherwise the char overload of the << operator will be used) so I recommend using plain int types for any integers by default.

    Using smaller types than int is only relevant if you read/write raw binary data, or you're on a very small embedded system where every single byte (or maybe even bit) counts.