0

How to use unsigned int properly? My function unsigned int sub(int num1, int num2);doesn't work when user input a is less than b. If I simply use int, we can expect a negative answer and I need to determine which is larger before subtracting. I know that's easy but maybe there is a way to use unsigned int to avoid that?

For instance when a = 7 and b = 4, the answer is 3.000000. But when I flip them, the code gives me 4294967296.000000 which I think is a memory address.

#include <stdio.h>

unsigned int sub(int num1,int num2){
    unsigned int diff = 0;
    diff = num1 - num2;
    return diff;
}

int main(){
    printf("sub(7,4) = %u\n", sub(7,4));
    printf("sub(4,7) = %u\n", sub(4,7));
}

output:

sub(7,4) = 3
sub(4,7) = 4294967293
Useless
  • 64,155
  • 6
  • 88
  • 132
reiallenramos
  • 1,235
  • 2
  • 21
  • 29
  • 1
    Converting from signed to unsigned doesn't result in taking the absolute value. It results in a [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic) conversion. – Cornstalks Apr 18 '17 at 14:30
  • 1
    What did you expect to get from the a=4, b=7 case? – M.M Apr 18 '17 at 14:30
  • @Cornstalks ahh you're right, absolute value must be the best way to do it – reiallenramos Apr 18 '17 at 14:31
  • 1
    Almost none of the posted code is at all relevant, and the bit that _is_ relevant depends on user input you didn't show. At least say what output you want. – Useless Apr 18 '17 at 14:32
  • @M.M I expect -3 but since it is unsigned, maybe it will drop the negative sign? Now that I think about it, maybe I misunderstood unsigned data types – reiallenramos Apr 18 '17 at 14:33
  • 2
    Yeah, `unsigned` means _without a sign_, which means it can't be negative. If you need to allow negative values, you can't use `unsigned`. Out of interest, what did you think it meant? – Useless Apr 18 '17 at 14:34
  • Good read: http://stackoverflow.com/questions/16056758/c-c-unsigned-integer-overflow – NathanOliver Apr 18 '17 at 14:34
  • @Cornstalks: Only for 2's complement representation. – too honest for this site Apr 18 '17 at 14:35
  • @useless im sorry, still figuring out the MCVE practice. I thought it would simply drop the negative sign, but after my quick research, it basically translates the whole int range into the right of 0. – reiallenramos Apr 18 '17 at 14:38
  • You want [`abs()`](http://en.cppreference.com/w/c/numeric/math/abs) for that. Using unsigned gives you the underflow behaviour described in the linked question and some of the answers. And, no problem - have a worked example of writing an MCVE. – Useless Apr 18 '17 at 14:39
  • @Useless wow thanks for editing. From how you edited my code, I take it that I don't need to present my hard code but only the essence. – reiallenramos Apr 18 '17 at 14:46
  • @Olaf: No, not just for 2's complement representation. The conversion from signed to unsigned is well defined, and is effectively a modular arithmetic conversion. For example, a signed `int` variable `n` converted to `unsigned int` results in a positive value that is equivalent to `n` modulo `UINT_MAX+1`. [Example](https://www.wolframalpha.com/input/?i=-12+mod+2%5E32) – Cornstalks Apr 18 '17 at 14:47
  • @Cornstalks: Ok, my fault, it is just "for free" (i.e. without extra operations) on 2's complement architectures, but has the same semantics on all three encodings. – too honest for this site Apr 18 '17 at 14:54
  • It's possible for `num1 - num2` to overflow (if `num1` and `num2` are of type `int`). For safety, you can use `if (num2 > num1) diff = (unsigned)num2 - (unsigned)num1; else diff = (unsigned)num1 - (unsigned)num2;` to get the absolute difference with no integer overflow. – Ian Abbott Apr 18 '17 at 14:58

5 Answers5

6

Unsigned numbers are unsigned... This means that they cannot be negative. Instead they wrap (underflow or overflow).

If you do an experiment with an 8-bit unsigned, then you can see the effect of subtracting 1 from 0:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint8_t i;

    i = 1;

    printf("i: %hhu\n", i);

    i -= 1;

    printf("i: %hhu\n", i);

    i -= 1;

    printf("i: %hhu\n", i);

    return 0;
}
i: 1
i: 0
i: 255

255 is the largest value that an 8-bit unsigned can hold (2^8 - 1).


We can then do the same experiment with a 32-bit unsigned, using your 4 - 7:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint32_t i;

    i = 4;

    printf("i: %u\n", i);

    i -= 7;

    printf("i: %u\n", i);

    return 0;
}
i: 4
i: 4294967293

4294967293 is effectively 0 - 3, which wraps to 2^32 - 3.


You also need to be careful of assigning an integer value (the return type of your sub() function) to a float... Generally this is something to avoid.

See below. x() returns 4294967293 as an unsigned int, but it is stored in a float... This float is then printed as 4294967296???

#include <stdio.h>
#include <stdint.h>

unsigned int x(void) {
    return 4294967293U;
}

int main(void) {
    float y;

    y = x();

    printf("y: %f\n", y);

    return 0;
}
y: 4294967296.000000

This is actually to do with the precision of float... it is impossible to store the absolute value 4294967293 in a float.

Attie
  • 6,690
  • 2
  • 24
  • 34
  • thank you for that very detailed explanation. Can I ask what type of identifier `uint8_t` is? – reiallenramos Apr 18 '17 at 15:03
  • 2
    @reiallenramos `uint8_t` is an unsigned integer type exactly 8 bits wide defined by `#include `. It is optional if the implementation has no such type available. – Ian Abbott Apr 18 '17 at 15:07
2

unsigned int cannot be used to represent a negative variable. I believe what you wanted is to find the absolute value of the difference between a and b. If so, you can use the abs() function from stdlib.h. The abs() function takes in an int variable i and returns the absolute value of i.

The reason why unsigned int returns a huge number in your case is due to the way integers are represented in the system. You declared diff as an int type, which is capable of storing a negative value, but the same sequence of bits that represents -3 when interpreted as unsigned int represents 4294967296 instead.

wto
  • 212
  • 1
  • 7
2

What you see is called unsigned integer overflow. As you noted, unsigned integers can't hold negative numbers. So when you try to do something that would result in a negative number, seemingly weird things can occour.

If you work with 32-bit integers,

  • int (int32_t) can hold numbers between (-2^31) and (+2^31-1), INT_MIN and INT_MAX
  • unsigned int (uint32_t) can hold numbers between (0) and (2^32-1), UINT_MIN and UINT_MAX

When you try to add something to an int that would lead to a number greater than the type can hold, it will overflow.

Venemo
  • 18,515
  • 13
  • 84
  • 125
0

It becomes a negative number, unsigned data types dont hold negative number, so instead it becomes a large number

Luke
  • 1
0

"absolute value of the difference between a and b" does not work for many combinations of a,b. Any a-b that overflows is undefined behavior. Obviously abs(INT_MAX - INT_MIN) will not generate the correct answer.

Also, using abs() invokes undefined behavior with a select value of int. abs(INT_MIN) is undefined behavior when -INT_MIN is not representable as an int.

To calculate the absolute value difference of 2 int, subtract them as unsigned.

unsigned int abssub(int num1,int num2){
  return (num1 > num2) ? (unsigned) num1 - num2 : (unsigned) num2 - num1;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256