4

I just tried to lower a unsigned int below 0. To my surprise it works!

#include<stdio.h>

int main(void)
{
        unsigned int foo = 5;
        foo -= 10;
        printf("%d", foo);
        return 0;
}

Compiled with

clang -Weverything main.c

This program returnes

-5

As this post and my personal knowledge states, it's not possible. But why does it work then? Am i missing something? Is it because of Undefined Behavior? Or is it printf? Or something else?

Community
  • 1
  • 1
Paul Kramme
  • 111
  • 1
  • 9
  • Ah. Thats what i thought about. How can i change it then? Which real value is it and how can i check it? – Paul Kramme Jul 10 '16 at 21:57
  • The `printf` effect has been answered already. Now, to verify that the compiler does not really believe that `foo` is negative, add the following at the end: `if(foo < 0) printf("this won't print");` – dxiv Jul 10 '16 at 22:12
  • Oh well. My idea was to use that as a state holder for a robot, and i wouldn't have to protect the below zero range. It isn't possible then :/ – Paul Kramme Jul 10 '16 at 22:14

3 Answers3

6

This program uses printf to re-interpret an unsigned int's value as a signed integer. Although this is not a problem when the value of unsigned int also fits in an int, it is undefined behavior:

If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined

Explanation: Subtracting ten from five "wraps around", so you get a large number based on your system's representation of unsigned int. It turns out that the bit representation of this large number corresponds to representation of negative five on your system, so when printf reinterprets the value as signed, negative five gets printed.

why isn't there any notice from compiler?

See this Q&A for a possible explanation.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

printf() is interpreting the value of foo as a signed integer. Try replacing %d with %u.

Edit: As dasblinkenlight said, this is undefined behavior. The programming language specification does not say what should be done if this happens, so it is left up to the implementation. Sometimes this may yield a different result, but in this case, it probably won't.

  • Thank you, why isn't there any notice from compiler then? What do other fuctions see? – Paul Kramme Jul 10 '16 at 22:00
  • Compilers don't issue warnings for all undefined behavior. I distinctly remember getting into an argument with someone one time about the value of sizeof(void). Void didn't have a size, but I kept insisting it was 4 because I was doing printf("%d\n", sizeof(void)); Also, the other answer on this question has an explanation of how exactly the value got interpreted as -5 if you want to read that :) –  Jul 10 '16 at 22:02
  • Undefined behaviour is not about showing a different value. The result of the operation is well defined. And `sizeof(void)` should generate an error. Anyway, `%d` for a `size_t` is also UB (as can be `%u`). – too honest for this site Jul 10 '16 at 22:12
  • @godisgood4_: Are you sure it was 4 and not 1? gcc defines `sizeof(void)` as `1`, as a side effect of implementing pointer arithmetic on `void*`. `sizeof(void)` is a constraint violation, requiring a diagnostic from any conforming compiler. gcc is not a conforming compiler by default; when you ask it to be one, it will warn about `sizeof(void)`. – Keith Thompson Jul 10 '16 at 23:05
  • I'm pretty sure it said 4 but I may not have been using GCC (I used Windows at the time and can't remember what compiler I was using. It was at least 2-3 years ago). @Olaf Thank you for pointing that out, undefined behavior is about the programming language not prescribing behavior, not about there being a different result on a different platform. –  Jul 10 '16 at 23:55
  • if you replace "%d" with "%u" you'll get a value=4294967291 (maybe different according to the size of int) – tryKuldeepTanwar Jul 11 '16 at 03:25
  • @godisgood4_:US is about **any** outcome being valid, including varying for different platforms and even between two different executions. – too honest for this site Jul 11 '16 at 07:38
0

Numbers on computers are stored in two's complement form. And a negative number represented in 2's complement is valid number in unsigned number's range. A processor core is cleverly implements addition/subtractions/multiplication/division such that it does not need to know the sign of the numbers to perform these operations. C language which make use of this core passed these numbers to arithmetic unit of processor which do the requested operation and return the result. That's why you got the result as expected on integers.

Ashwani
  • 104
  • 5