How does subtracting the character ‘0’ from a char change it into an int?

Posted on

How does subtracting the character ‘0’ from a char change it into an int?

This method works in C, C++ and Java. I would like to know the science behind it.

The value of a char can be 0-255, where the different characters are mapped to one of these values. The numeric digits are also stored in order '0' through '9', but they’re also not typically stored as the first ten char values. That is, the character '0' doesn’t have an ASCII value of 0. The char value of 0 is almost always the null character.

Without knowing anything else about ASCII, it’s pretty straightforward how subtracting a '0' character from any other numeric character will result in the char value of the original character.

So, it’s simple math:

'0' - '0' = 0  // Char value of character 0 minus char value of character 0
// In ASCII, that is equivalent to this:
48  -  48 = 0 // '0' has a value of 48 on ASCII chart

So, similarly, I can do integer math with any of the char numberics…

(('3' - '0') + ('5' - '0') - ('2' - '0')) + '0') = '6'

The difference between 3, 5, or 2 and 0 on the ASCII chart is exactly equal to the face value we typically think of when we see that numeric digit. Subtracting the char '0' from each, adding them together, and then adding a '0' back at the end will give us the char value that represent the char that would be the result of doing that simple math.

The code snippet above emulates 3 + 5 - 2, but in ASCII, it’s actually doing this:

((51 - 48) + (53 - 48) - (50 - 48)) + 48) = 54

Because on the ASCII chart:

0 = 48
2 = 50
3 = 51
5 = 53
6 = 54

In C the + and - operators apply integer promotion*1 to their arguments, thus the result of subtracting (or adding) two chars is an int*2.

From the C-Standard: Program execution


10 EXAMPLE 2 In executing the fragment

char c1, c2;
/* ... */
c1 = c1 + c2;

the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size and then add the two ints […]

Applying this to the OP’s implicitly given use case of

char c = 42;
... = c - `0`;

This would be lead to the above being the same as:

... = (int) c - (int) `0`; /* The second cast is redundant, as per Jens' comment. */              
      ^                ^
      +------ int -----+

*1: If the operators arguments have a lower rank than int they are promoted to an int.

*2: char has a lower rank than int.

There’s no change going on. '0' is an int in C. It is a fancy way to write 48 (assuming ASCII).

You can convince yourself of this fact by computing the size of '0':

  printf ("sizeof '0'   is %zun", sizeof '0');
  printf ("sizeof(char) is %zun", sizeof(char));

which in the first line very likely prints 4 (or 2) but probably not 1 like in the second row (again: in C; it’s different for C++).

The numeric constant 0, without any qualifications, has type int. The result of the binary subtraction operation on a char and an int also has type int due to the usual type promotion process.

Leave a Reply

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