4

I am a student, going through the book by Kerningham and Ritchie for C.

A line in the book says that -1l is less than 1u because in that case unsigned int is promoted to signed long. But -1l > 1ul because in this case -1l is promoted to unsigned long.

I can't really understand the promotion properly. What will be the value of -1l when it is promoted to unsigned long? It'll be great if anyone can help. Thanks.

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
Rohit Jain
  • 831
  • 3
  • 12
  • 22
  • Don't you mean: "But -1l > 1ul because in this case -1l is promoted to **`unsigned`** `long`. – rubenvb Jun 14 '11 at 19:17
  • 2
    Hey, don't fall for the "answer with the highest votes and at the top must be best and I'll just accept that one"... Decide for yourself, nd give credit to the person that put the most time and clarity in his/her answer. – rubenvb Jun 14 '11 at 20:31

4 Answers4

2

In -1l > 1ul the -1l is promoted to unsigned long, and by definition and Standard, -1 cast to an unsigned type will be the largets value representable by that unsigned type.

I got my inspiration from memory of this answer here to a quite relevant question.

And after looking at the C99 draft I have lingering around, see for example 6.3.1.3(2), where it says the maximum value representable by the type will be added or subtracted from the original value until it fits in the new type. I must warn you that char, although it is an integer type, is treated special: it is implementation defined if char is signed or unsigned. But that is, strictly, beside the question at hand.

Community
  • 1
  • 1
rubenvb
  • 74,642
  • 33
  • 187
  • 332
1

Implicit promotions are one of the most difficult things in the C language. If you have a C code expression looking like

if(-1l > 1ul)

then no "integer promotions" take place. Both types are of the same size, but different signedness. -1l will then be converted to unsigned long with a very large value. This is one of the rules in the "usual arithmetic conversions".

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

This is actually a conversion. Promotions go from types with less rank than an integer to integer.

The rules for integer conversions in C are somewhat complex. They are, as per ISO C99 §6.3.1.8 ¶1:

Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

If both operands have the same type, then no further conversion is needed.

Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

I'll try to explain them:

Try to convert to the larger type. When there is conflict between signed and unsigned, if the larger (including the case where the two types have the same rank) type is unsigned, go with unsigned. Otherwise, go with signed only in the case it can represent all the values of both types.

ninjalj
  • 42,493
  • 9
  • 106
  • 148
  • What you cite is the usual arithmetic conversions. The integer promotions are the conversion that takes place of smaller types like char and short, whenever they appear in any expression. The integer promotions are found at 6.3.1.1. – Lundin Jun 14 '11 at 20:01
  • 1
    Fair enough, though to be picky there's also other promotions, like the oddity called "the default argument promotions". – Lundin Jun 14 '11 at 20:33
0

When you're learning C, if you have a question, just write yourself a simple program:

#include <stdio.h>
main() {
  int si = -1;
  unsigned int ui = 1;
  if ( si > ui ) printf("-1l > 1u\n");
  else           printf("-1l <= 1u\n");
}

You'll see that -1l > 1u is shown for the output.

Because both si and ui have the same rank (they're both ints), the rule says that the negative value will be promoted to unsigned at set to UINT_MAX which is the largest possible unsigned value.

unpythonic
  • 4,020
  • 19
  • 20
  • -1: This is a great way to discover implementation defined behavior and label that as standard. Although your answer is correct, I feel that trial and error "Just Doesn't Cut It" when there's implementation defined behavior... – rubenvb Jun 14 '11 at 19:32
  • @rubenvb - `gcc -std=c99 test.c`. So when your program doesn't work, you include a note that says it would work if only your compiler wasn't messed up? I think this kind of rudimentary question can be safely answered by testing. – unpythonic Jun 14 '11 at 19:35
  • You'd be surprised at what is undefined when you test anything you throw at it. Stuff like `sizeof` will differ immensely from platform to platform, to give only a simple example. And all the differences are perfectly legal. And undefined behavior != "program doesn't work". It may work, it may not, it may eat your children, it may give you a high five. – rubenvb Jun 14 '11 at 19:38
  • no, the result will differ depending on the size of integer types. – ninjalj Jun 14 '11 at 20:27
  • @ninjalj: I agree, that's why I said "same rank" (quoting from my reference). Saying "same size" would probably have been clearer. – unpythonic Jun 14 '11 at 22:33