30

I have the following code:

#include <stdio.h>

int main() {
    unsigned int a = -1;
    int b = -1;
    printf("%x\n", a);
    printf("%x\n", b);

    printf("%d\n", a);
    printf("%d\n", b);

    printf("%u\n", a);
    printf("%u\n", b);
    return 0;
}

The output is:

ffffffff
ffffffff
-1
-1
4294967295
4294967295

I can see that a value is interpreted as signed or unsigned according to the value passed to printf function. In both cases, the bytes are the same (ffffffff). Then, what is the unsigned word for?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rvillablanca
  • 1,606
  • 3
  • 21
  • 34
  • See: [**Two's complement - Wikipedia, the free encyclopedia**](https://en.wikipedia.org/wiki/Two%27s_complement) The short answer is "if the most significant bit is `1`, it is interpreted as a **negative** integer". – David C. Rankin Sep 02 '15 at 04:51
  • http://www.cplusplus.com/forum/beginner/94567/ – karan Sep 02 '15 at 04:55
  • Yes, but that is done by `printf` function, then, I cannot understand what role plays the `unsigned` word. In my example, for both signed and unsigned vars I could see its value as signed or unsigned. To clarify, if I can see a signed var printed as signed or unsigned, what is `unsigned` word for? – rvillablanca Sep 02 '15 at 05:02
  • 5
    @rvillablanca "if I can see a signed var printed as signed or unsigned" – you can't, printing an unsigned value using `%d` and printing a signed value using `%u` or `%x` is **undefined behavior.** – The Paramagnetic Croissant Sep 02 '15 at 05:13
  • But both vars have the same bytes values `ffffffff`, then, It should not be undefined behavior because printing `ffffffff` can be printed as signed `-1` or unsigned `4294967295` – rvillablanca Sep 02 '15 at 05:21
  • 3
    Some of your printf statements are UB, which dominates this question. – David Heffernan Sep 02 '15 at 05:45
  • 2
    It's undefined behavior. No one can understand what you mean by "printing ffffffff can be printed as signed -1 or unsigned 4294967295". The same bit pattern can be treated as signed or unsigned in printf using the corresponding format if you cast the value to the correct type first. – phuclv Sep 02 '15 at 05:53
  • `unsigned` is for the compiler as C doesn't require 2's complement signed type. And even in 2's complement some operations produce different results for signed and unsigned types like division – phuclv Sep 02 '15 at 06:03
  • 2
    possible duplicate of [What happens when I assign a negative value to an unsigned int?](http://stackoverflow.com/questions/7152759/what-happens-when-i-assign-a-negative-value-to-an-unsigned-int) – Bo Persson Sep 02 '15 at 07:43

3 Answers3

30

Assign a int -1 to an unsigned: As -1 does not fit in the range [0...UINT_MAX], multiples of UINT_MAX+1 are added until the answer is in range. Evidently UINT_MAX is pow(2,32)-1 or 429496725 on OP's machine so a has the value of 4294967295.

unsigned int a = -1;

The "%x", "%u" specifier expects a matching unsigned. Since these do not match, "If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined." C11 §7.21.6.1 9. The printf specifier does not change b.

printf("%x\n", b);  // UB
printf("%u\n", b);  // UB

The "%d" specifier expects a matching int. Since these do not match, more UB.

printf("%d\n", a);  // UB

Given undefined behavior, the conclusions are not supported.


both cases, the bytes are the same (ffffffff).

Even with the same bit pattern, different types may have different values. ffffffff as an unsigned has the value of 4294967295. As an int, depending signed integer encoding, it has the value of -1, -2147483647 or TBD. As a float it may be a NAN.

what is unsigned word for?

unsigned stores a whole number in the range [0 ... UINT_MAX]. It never has a negative value. If code needs a non-negative number, use unsigned. If code needs a counting number that may be +, - or 0, use int.


Update: to avoid a compiler warning about assigning a signed int to unsigned, use the below. This is an unsigned 1u being negated - which is well defined as above. The effect is the same as a -1, but conveys to the compiler direct intentions.

unsigned int a = -1u;
Neuron
  • 5,141
  • 5
  • 38
  • 59
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Your statement about UB is incorrect. Please re-read the paragraphs above the one you quoted. TL;DR: Any conversion-specifier that follows the grammar is "valid". In other words in `printf("%d", "foo")` the specifier "%d" is valid, in the sense the quoted paragraph refers to. Of course trying to print a string as an int is UB, but not because of the reason you seem to think. Rather "the proper type promotion or conversion is performed, if allowed" and since no type promotion or conversion is allowed from string to int, it becomes UB. – AnorZaken Oct 24 '17 at 12:57
  • @AnorZaken Answer amended to emphasize that the printf specifier and argument type do not match. – chux - Reinstate Monica Oct 24 '17 at 14:07
  • Err, why would specifier %u be undefined for unsigned integer `b`? – Columbo May 12 '20 at 09:22
  • @Columbo With `int b = -1;`, `b` is not a _unsigned integer_, but an `int` with the value of -1. Printing with a mis-matched specifier is UB - there is an exception with positive numbers, but that does not apply here. – chux - Reinstate Monica May 12 '20 at 14:47
  • That's so misreadable, because you solely quote the definition of `a`, and then proceed to use `b`. Quote both definitions in your answer, please. – Columbo May 12 '20 at 15:14
0

Having unsigned in variable declaration is more useful for the programmers themselves - don't treat the variables as negative. As you've noticed, both -1 and 4294967295 have exact same bit representation for a 4 byte integer. It's all about how you want to treat or see them.

The statement unsigned int a = -1; is converting -1 in two's complement and assigning the bit representation in a. The printf() specifier x, d and u are showing how the bit representation stored in variable a looks like in different format.

Donotalo
  • 12,748
  • 25
  • 83
  • 121
0

When you initialize unsigned int a to -1; it means that you are storing the 2's complement of -1 into the memory of a.
Which is nothing but 0xffffffff or 4294967295.

Hence when you print it using %x or %u format specifier you get that output.

By specifying signedness of a variable to decide on the minimum and maximum limit of value that can be stored.

Like with unsigned int: the range is from 0 to 4,294,967,295 and int: the range is from -2,147,483,648 to 2,147,483,647

For more info on signedness refer this

Santosh A
  • 5,173
  • 27
  • 37