-1

I have been reading KnR lately and have come across a statement:

"Type conversions of Expressions involving unsigned type values are complicated"

So to understand this i have written a very small code:

#include<stdio.h>
int main()
{
    signed char x = -1;
    printf("Signed : %d\n",x);
    printf("Unsigned : %d\n",(unsigned)x);
}
  • signed x bit form will be : 1000 0001 = -1
  • when converted to unsigned its value has to be 1000 0001 = 129. But even after type conversion it prints the -1.

Note: I'm using gcc compiler.

WedaPashi
  • 3,561
  • 26
  • 42
  • This behavior is rather uninteresting as `%d` means "treat whatever I pass to printf as a signed int". And also, since printf is variadic function, there is an implicit type promotion of the passed parameter to `int`, if the parameter is a small type. – Lundin Aug 31 '18 at 06:49
  • Personal advise: burn K&R with fire, then read [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules). – Lundin Aug 31 '18 at 06:55
  • @Lundin, Then admit that was a bad idea and purchase two more copies to allow for one more lapse of judgement ;-) – Bathsheba Aug 31 '18 at 07:47
  • @Bathsheba If you want, we can play the game where you pick one random page in K&R. If I can find any typo, incorrect statement, reliance on poorly-defined behavior or blatant violation of C programming de facto good practice, we burn that page. You get to keep what's left. Not even the cover will remain though... – Lundin Aug 31 '18 at 07:54
  • @Lundin: I'm in. Let's have lunch with Brian first. He tends to come to Oxford in the summer. The question remains though, are we going to use `rand()` to pick the pages?! – Bathsheba Aug 31 '18 at 07:56
  • 2
    @Bathsheba Alas the page mentioning `rand` (p43) contains the text "The cast operator has the same high precedence as other unary operators, as summarized in the table at the end of this chapter" which is blatantly incorrect and points at the equally incorrect precedence table. See C17 6.5.4 syntax: `cast-expression: unary-expression ( type-name ) cast-expression`. This was also true in C90, so the book was already incorrect back in 1989. Now I burnt the page containing this misleading information, so we can't use `rand` :( – Lundin Aug 31 '18 at 08:03

2 Answers2

0

C11 6.3.1.3, paragraph 2:

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

−1 cannot be represented as an unsigned int value, the −1 is converted to UINT_MAX. Thus -1 becomes a very large positive integer.

Also, use %u for unsigned int, otherwise result invoked undefined behaviour.

msc
  • 33,420
  • 29
  • 119
  • 214
0

C semantics regarding conversion of integers is defined in terms of the mathematical values, not in terms of the bits. It is good to understand how values are represented as bits, but, when analyzing expressions, you should think about values.

In this statement:

printf("Signed : %d\n",x);

the signed char x is automatically promoted to int. Since x is −1, the new int also has the value −1, and printf prints “-1”.

In this statement:

printf("Unsigned : %d\n",(unsigned)x);

the signed char x is automatically promoted to int. The value is still −1. Then the cast converts this to unsigned. The rule for conversion to unsigned is that UINT_MAX+1 is added to or subtracted from the value as needed to bring it into the range of unsigned. In this case, adding UINT_MAX+1 to −1 once brings the value to UINT_MAX, which is within range. So the result of the conversion is UINT_MAX.

However, this unsigned value is then passed to printf to be printed with the %d conversion. That violates C 2018 7.21.6.1 9, which says the behavior is undefined if the types do not match.

This means a C implementation is allowed to do anything. In your case, it seems what happened is:

  • The unsigned value UINT_MAX is represented with all one bits.
  • The printf interpreted the all-one-bits value as an int.
  • Your implementation uses two’s complement for int types.
  • In two’s complement, an object with all one bits represents −1.
  • So printf printed “-1”.

If you had used this correct code instead:

    printf("Unsigned : %u\n",(unsigned)x);

then printf would print the value of UINT_MAX, which is likely 4,294,967,295, so printf would print “4294967295”.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312