Converting char to int using typecasting makes 1s into 49 and 0s into 48 in C?

Viewed 311

I have a one byte char array consisting of a binary value and I am trying to split it into a two-dimensional int array (low nybble and high nybble). This is my code:

int nybbles[2][4]; //[0][] is low nybble, [1][] is high nybble.
for (int i = 0; i < 4; i++) {
    nybbles[0][i] = (int)binarr[i];
    nybbles[1][i] = (int)binarr[4 + i];
    printf("%c%d ", binarr[i], nybbles[0][i]);
    printf("%c%d\n", binarr[4 + i], nybbles[1][i]);
}

The output of this is:

048
149
048
048
149
048
048
048

I can easily fix this by adding a "- 48" to the end of both lines of code, as such:

nybbles[0][i] = (int)binarr[i] - 48;
nybbles[1][i] = (int)binarr[4 + i] - 48;

However, I see this as a very brute force solution. Why does this problem exist anyway? Are there better fixes than mine?

5 Answers

The values 48 and 49 are the ASCII codes for the characters '0' and '1'.

Rather than subtracting 48, subtract '0'. This makes it more clear what you're doing.

nybbles[0][i] = binarr[i] - '0';
nybbles[1][i] = binarr[4 + i] - '0';

Characters are encoded using numeric values, in ASCII, '0' code is 48, '1' is 49 and so on, what you are doing is using this to deduce the integer values of these characters.

Example:

'0' - '0' is equal to 0, why? Because 48 - 48 is equal to 0, just as '1' - '0' is equal to 1, meaning 49 - 48 is equal to 1, you see the pattern.

There is no brute force, just character arithmetic, it's quite common. I would just use:

nybbles[0][i] = binarr[i] - '0';

Besides being clearer, it's more portable given that ASCII is not the only encoding in existance, but all of them have contiguous digit encoding.

The number zero is not the same as the digit "0". On your platform, the code for the digit "0" happens to be 48.

Fundamentally, values and representations are different. Ten is the number of fingers I have. It can be represented as "X", "10", "0x0A", "ten", or "..........".

The digit "0" can be used to represent the value zero. Or it can be used for other purposes. Regardless of what you use it for, on your platform that character is represented by the character code whose value is forty-eight.

It is absolutely vital for programmers to understand that values and representations are different things. Use '0' when you need the value your platform uses to represented the character "0".

This is because of the conversion between ASCII and byte values. The computer just sees bytes (numbers), and those numbers mean different things depending on the context. When we're talking about characters and strings we're normally talking about ASCII text encoding. It has its own system. For instance, the value 0 is null in ASCII. The value 48 is 0 in ASCII. 57 is 9 in ASCII. 65 is A in ASCII. Interesting right? So, to get the correct ASCII digit from a byte value, you must subtract the ASCII offset (the numerical digits start at number 48, therefore subtract 48). The capital letters have an offset of 65, on the other hand.

Doing a search with terms such as "ascii byte binary table values comparison" will bring you to pages like this IBM-provided table.

The best solution in code is to use a to_string function, which is available in most languages. In C, you might have to look for a good external library, or just live with the arithmetic.

You experience this behavior because the digits you get from the original string are characters encoded in ASCII format.

So, 48 = 0x30 and 49 = 0x31 are the ASCII values to represent '0' and '1' characters respectively.

For the record, the "brute" force subtraction is how usually digit characters are converted to the corresponding integer values. The following expression is just to understand how it works

char charDigit = '4';
int digit = charDigit - 48; // digit is equal to integer 4, because '4' is ecoded by 52 (0x34 in hex)

Even better (it is the expression that is actually commonly used):

char charDigit = '4';
int digit = charDigit - '0'; // digit is equal to integer 4

It is better because it works not only for ASCII encoding.

Related