user4182981
user4182981

Reputation:

Why does C++ converts a signed int to an unsigned int in an expression?

When comparing an int to an unsigned int, for example:

signed int si = -1;
unsigned int ui = 0;

if (ui > si)
{
    // Do something
}

si will be converted to an unsigned int and so it will be bigger than ui. So why is this even allowed if the result will not be as expected, is it made this way for historical reasons, and if they had to do it again they wouldn't allow it?

Upvotes: 2

Views: 817

Answers (4)

Phil Mayes
Phil Mayes

Reputation: 31

There are only two choices for the language:

  • treat the signed as unsigned
  • treat the unsigned as signed

As dasblinkenlight says, the language mandates the former. The reason is that it makes the code simpler. In modern machines, the top bit is the sign bit, and the hardware can perform either a signed or an unsigned comparison, so the code is just a compare followed by an unsigned conditional jump.

To treat the unsigned as signed, the compiler could throw away (mask out) the top bit in the unsigned word ui and then perform a signed test, but that would change its value. Alternatively it could test the top bit of ui first and return greater if set, then perform the masking above.

Bottom line, the language choice was made because it's more code-efficient.

Upvotes: 0

M.M
M.M

Reputation: 141544

This rule exists because it is the best solution to the problem.

You can't compare apples and oranges. The only options are:

  • convert orange to apple
  • convert apple to orange
  • convert both to some other common type

Out of the first two options, converting both to unsigned makes more sense than converting both to signed.

How about the third option? I suppose a possibility would be to convert both values to long and then do the comparison. This might seem like a good idea at first, but if you think about it some more then there are some problems:

  • If long and int are the same size then this doesn't actually help
  • Even if long is bigger than int, you have just moved the problem off to the case of comparing a long with an unsigned long .
  • It would be harder to write portable code.

The last point is important. The historical rules about short and char being promoted to int are actually extremely annoying when you are writing template code or code with overloaded functions, because it changes which overload is called.

We would not want to introduce any more rules of the same type (e.g. promote int to long if it is in comparison with unsigned int but only if sizeof(long) > sizeof(int) yada yada yada).

Upvotes: 2

Ralph Tandetzky
Ralph Tandetzky

Reputation: 23600

The reason is mostly historical. C++ is big on being compatible with C code even today. You can take a C code-base and convert it verbatim to C++ and it will probably work, even though there are some minor differences and incompatibilities. C has defined it that way and C++ will not change it, because otherwise it would change the meaning of code and therefore break programs that would otherwise work.

In the current working draft (N4296) you can find the rules in section 5.10.5.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

C++ has the following rules for deciding the type to which the two values are converted after integer promotions have been done (chapter 5, clause 9):

  • If both operands have the same type, 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 shall be converted to the type of the operand with greater rank.
  • Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be 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, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.
  • Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

The last rule applies here, because both int and unsigned int have the same rank.

Upvotes: 5

Related Questions