How does std::cout convert numerical types to base 10?

Viewed 251

I've learned that numerical types, such as int and long long, are stored in a base-two format in C++. These individual bits can be accessed and modified using bitwise operators.

However, I recently wondered why numbers weren't printed to the screen from std::cout in base 2 as well, and thought that they must've been converted to base 10 before being printed. In other words, since std::cout outputs these numbers in base 10, I think that there must be some conversion process going on to convert these numbers from base-2 to base-10.

Overall, my question is, does std::cout actually convert numbers from base 2 to base 10, and how does it do so? Am I making some other logical mistake here?

2 Answers

I find the libstdc++ (gcc's standard library) source almost unnavigable, but I think the meat of it is done here:

https://github.com/gcc-mirror/gcc/blob/8e8f6434760cfe2a1c6c9644181189fdb4d987bb/libstdc%2B%2B-v3/include/bits/locale_facets.tcc#L794

Which appears to use the good ol' "divide by 10 and print remainder" technique for decimal digits:

do
  {
    *--__buf = __lit[(__v % 10) + __num_base::_S_odigits];
    __v /= 10;
  }
while (__v != 0);

To break this down a bit, remember that the char type is just a number, and when you write a char, it looks the character up in a table. In both the old ASCII and newer UTF-8 character encodings, '0' is 48, '1' is 49, '2' is 50, etc. This is extremely convenient because you can print any digit 0-9 by adding it to '0':

putchar('0' + 3) // prints 3

So, to get each digit, divide by 10 and the remainder is the last digit:

int x = 123;
putchar('0' + (x % 10)) // prints '0' + 3, or '3'
x = x / 10;             // x = 12
putchar('0' + (x % 10)) // prints '0' + 2, or '2'
x = x / 10;             // x = 1
putchar('0' + (x % 10)) // prints '0' + 1, or '1'
x = x / 10;             // x = 0, stop

The snippet from the library is just doing that in a loop.

You'll notice the code prints the digits backwards. That's why the snippet from the library decrements the character pointer each iterator (*--__buf = ...) - it's starting at the right and printing it in reverse right-to-left.

Don’t get hung up on how the value is represented in the computer. It doesn’t matter. To convert a value to a representation in base 10, just pick off digits one at a time. The remainder when you divide a value by 10 is the lowest digit in the base 10 representation. To pick off all the digits, just keep taking the remainder:

while (value != 0) {
    std::cout << value % 10;
    value = value / 10;
}

That prints out the digits in the base-10 representation of value. To build a string representation of value, convert each digit to a character (by adding ’\0’) and store the characters into an array. If you store the characters from right to left (the most natural way) you’ll have to remember to reverse them afterwards. If you store them from left to right they’ll be in the right order.

Related