Ajay Pal
Ajay Pal

Reputation: 563

Subtraction of Hexadecimal values using char in C

I am having a hard time understanding the output of the following program.

int main(){
    char y = 0x02;
    y = y-0x03;
    printf("0x%x  %d",y,sizeof(y));
    return 0;
}

The output that I am getting is

0xffffffff 1

I know so far is that if I add two hexadecimal values their binary values are added. The same is done for subtraction using the concept of borrow (please correct me if I am wrong)

Examples
111 - 001 = 110 (in binary) 110 - 001 = 101 (using carry from second LSB in first operand)

In the case of addition of two hexadecimal values if the values overflow char they are basically mod 256. That is if I write a program as

int main(){
   char y = 0x03;
   y = y+0xff;
   printf("0x%x",y);
   return 0;
}

I will get output of

0x2

But in case of subtraction, if I run the first program, the expected output should be

0xff

So my question is since the above subtraction should be

00000010 - 00000011

in binary, where the borrow is coming from? and why I am getting this

0xffffffff

weird output?

Upvotes: 1

Views: 3414

Answers (4)

NomeQueEuLembro
NomeQueEuLembro

Reputation: 112

This happens because of a tricky concept called integer promotions.

Basically, your single-byte char are being converted to 4-byte integers to handle your operations. So:

0x02 - 0x03

Becomes:

0x00000002 - 0x00000003

Which happens to be 0xffffffff (because that's how -1 is represented as an integer).

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753615

Two parts to the answer:

  1. Arguments to printf() — or the ... portion of any variadic function — undergo default promotion. For type char, that means the value is converted to int.

  2. You have signed char on your machine, so the value is sign-extended. That is, the 0xFF stored in y is converted to 0xFFFFFFFF, which is what you see printed.

If you have a library that supports a sufficiently modern specification of printf(), you could use:

printf("%hhx %zu\n", y, sizeof(y));

The hhx says 'convert to char and then print'. The z length modifier %zu is one of the correct formats for printing size_t values such as those returned by sizeof(). Failing that, use y & 0xFF or (unsigned char)y instead of a plain y as the argument to printf().

Upvotes: 4

Ari0nhh
Ari0nhh

Reputation: 5920

I know so far is that if I add two hexadecimal values they are converted to binary and then are added. The same is done for subtraction using the concept of borrow (please correct me if I am wrong)

You are wrong. Hexadecimal, decimal, octal, etc is a form to represent a number. Down below it is always a sequence of bits.

You are getting "weird" output because of %x format specification. Your 1 byte char value is converted to the unsigned int.

Upvotes: 1

Most computer systems today use two's complement to represent negative numbers. In this system, negative numbers are represented as the bitwise inverse of one less than their absolute value. Negative one represented in this way is the bitwise inverse of 1 - 1 = 0, which has all of its bits on.

Also, note that signed overflow is undefined behavior in C, so unless you use a compiler option like gcc's -fwrapv, so your example with mod 256 above isn't guaranteed to work.

Upvotes: 0

Related Questions