4

Hi I'm currently learning C and there's something that I quite don't understand. First of all I was told that if I did this:

unsigned int c2 = -1;
printf("c2 = %u\n", c2);

It would output 255, according to this table:

table

But I get a weird result: c2 = 4294967295

Now what's weirder is that this works:

unsigned char c2 = -1;
printf("c2 = %d\n", c2);

But I don't understand because since a char is, well, a char why does it even print anything? Since the specifier here is %d and not %u as it should be for unsigned types.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
MM1
  • 912
  • 1
  • 10
  • 28

3 Answers3

2

The following code:

unsigned int c2 = -1;
printf("c2 = %u\n", c2);

Will never print 255. The table you are looking at is referring to an unsigned integer of 8 bits. An int in C needs to be at least 16 bits in order to comply with the C standard (UINT_MAX defined as 2^16-1 in paragraph §5.2.4.2.1, page 22 here). Therefore the value you will see is going to be a much larger number than 255. The most common implementations use 32 bits for an int, and in that case you'll see 4294967295 (2^32 - 1).

You can check how many bits are used for any kind of variable on your system by doing sizeof(type_or_variable) * CHAR_BIT (CHAR_BIT is defined in limits.h and represents the number of bits per byte, which is again most of the times 8).

The correct code to obtain 255 as output is:

unsigned char c = -1;
printf("c = %hhu\n", c);

Where the hh prefix specifier means (from man 3 printf):

hh: A following integer conversion corresponds to a signed char or unsigned char argument, or a following n conversion corresponds to a pointer to a signed char argument.

Anything else is just implementation defined or even worse undefined behavior.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
1

In this declaration

unsigned char c2 = -1;

the internal representation of -1 is truncated to one byte and interpreted as unsigned char. That is all bits of the object c2 are set.

In this call

printf("c2 = %d\n", c2);

the argument that has the type unsigned char is promoted to the type int preserving its value that is 255. This value is outputted as an integer.

Is this declaration

unsigned int c2 = -1;

there is no truncation. The integer value -1 that usually occupies 4 bytes (according to the size of the type int) is interpreted as an unsigned value with all bits set.

So in this call

printf("c2 = %u\n", c2);

there is outputted the maximum value of the type unsigned int. It is the maximum value because all bits in the internal representation are set. The conversion from signed integer type to a larger unsigned integer type preserve the sign propagating it to the width of the unsigned integer object.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

In C integer can have multiple representations, so multiple storage sizes and value ranges refer to the table below for more details.

enter image description here

Saif Faidi
  • 509
  • 4
  • 15
  • 1
    The table you show (and which can't be copy-pasted from, or used by screen readers, please don't post images) are the most common ranges and sizes. Except for `long`, which could be 4 bytes (32 bits) even on a 64-bit system (e.g. Micosoft Visual C++ uses 32-bit `long`). And it misses the 64-bit (at *least*) type `long long`. – Some programmer dude Mar 24 '20 at 17:10
  • 1
    This doesn't answer the question and the table is just showing *some* of the many valid implementations of the standard. – Marco Bonelli Mar 24 '20 at 17:12