6

Here is very simple code,

#include <iostream>
using namespace std;
int main() {
    unsigned int u=10;
    int i;
    int count=0;
    for (i=-1;i<=u;i++){
        count++;
    }
    cout<<count<<"\n";
    return 0;
}

The value of count is 0. Why?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    As an aside, you should use `std::endl` instead of inserting `\n` into a stream, because `std::endl` both is portable and ensures the output is displayed immediately. – Ben Voigt Aug 02 '10 at 04:57
  • 1
    @Ben: `\n` is just as portable; you should only use `endl` if you particularly want the stream flushed now. – Mike Seymour Aug 02 '10 at 10:55
  • `\n` is portable (it gets converted to the platform's line break sequence), and doesn't carry the overhead of immediately flushing the stream. You should use the one that has the semantics you want: if you want the stream to be flushed, use `endl`, if you just want a line break, use `\n`. – jalf Sep 27 '10 at 23:06
  • 1
    std::endl is the equivalent of "\n" << std::flush and as has been said, flush has overhead. – sqqqrly Jun 11 '13 at 16:00

5 Answers5

9

Both operands of <= have to be promoted to the same type.

Evidently they are promoted to unsigned int (I don't have the rule from the standard in front of me, I'll look it up in a second). Since (unsigned int)(-1) <= u is false, the loop never executes.

The rule is found in section 5 (expr) of the standard, paragraph 10, which states (I've highlighted the rule which applies here):

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

  • If either operand is of scoped enumeration type (7.2), no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.
  • If either operand is of type long double, the other shall be converted to long double.
  • Otherwise, if either operand is double, the other shall be converted to double.
  • Otherwise, if either operand is float, the other shall be converted to float.
  • Otherwise, the integral promotions (4.5) shall be performed on both operands. 60 Then the following rules shall be applied to the promoted operands:
  • 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.
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
4

During the comparison (i <= u), i is upgraded to an unsigned integer, and in the process -1 is converted to UINT_MAX.

A conversion of a negative number to an unsigned int will add (UINT_MAX + 1) to that number, so -1 becomes UINT_MAX, -2 becomes UINT_MAX - 1, etc.

If you think about it, one had to be converted to the other in order for the comparison to even work, and as a rule the compiler converts the signed value to unsigned. In this case, of course, it'd make more sense to convert the unsigned value to signed instead, but the compiler can't just decide to follow a different spec based on what you intend. You should explicitly cast the unsigned int to signed (or just have it as signed all along) here.

thomasrutter
  • 114,488
  • 30
  • 148
  • 167
  • Your rule doesn't work. Actually 2**32 is added, which is `UINT_MAX + 1`, not `UINT_MAX - 1`. – Ben Voigt Aug 02 '10 at 04:16
  • 1
    WRT your new comments, the conversion from signed to unsigned is well-defined for all inputs, but the conversion from unsigned to signed can invoke implementation-defined behavior (here it wouldn't, since the value of `u` is 10 which fits in `int`). – Ben Voigt Aug 02 '10 at 04:25
  • Yes, when I advised using or casting to a signed int for `u` that is assuming `u` remains within the allowed range for a signed int. If you are likely to exceed this and you really need unsigned, you'll have to rethink the code a bit - like not starting `i` at minus one perhaps. – thomasrutter Aug 02 '10 at 07:23
1

Its because -1 is casted as an unsigned int, so the for loop code is never executed.

Try compiling with -Wall -Wextra so you can get the respective warnings (if not getting them so far, and compiling with g++)

http://en.wikipedia.org/wiki/Two's_complement

Tom
  • 43,810
  • 29
  • 138
  • 169
  • thanks just i want to ask you one thing i will give link to my question and please tell me reason why they decrease my mark or they downvote ok? i want to have good reputation mark and trying to post good questions but they decreases it –  Aug 02 '10 at 04:08
  • 1
    @davit: Your other question got downvoted because the compiler told you exactly what was wrong (you were missing a semicolon) but you posted your question here without even trying to solve the problem yourself. – Ben Voigt Aug 02 '10 at 04:20
1

This is because i is promoted to an unsigned value before comparison. This will set it to the value of UINT_MAX, which on a 32 bit machine equals to 4294967295. So your loop is essentially the same as:

// will never run
for (i = 4294967295; i <= u; i++) {
    count++;
}
Vijay Mathew
  • 26,737
  • 4
  • 62
  • 93
0

On a system where an integer is stored in 4 bytes, I believe that the value of -1 equals the value of 2147483649 (1000 0000 0000 0000 0000 0000 0000 0001) - It's 1 with the MSB set to 1 to indicate it's negative.

ndrix
  • 1,191
  • 12
  • 18
  • 1
    No, in two's complement representation `-1` is stored as all ones. But the actual representation doesn't matter, because the C++ standard defines conversion from a signed to an unsigned integral type as congruent in module base-N arithmetic. – Ben Voigt Aug 02 '10 at 04:18
  • 1
    While that would be true on a sign-magnitude system, those are now exceedingly rare. Most reasonably current systems use 2's complement for integers, and in this case -1 will be represented by all bits set to 1 (in which case the conversion from signed to unsigned requires no change in the data at all, only a change in how it's interpreted). – Jerry Coffin Aug 02 '10 at 04:20
  • 1
    @Jerry: sign-magnitude is not rare at all. IEEE 754 requires it. Virtually every computer uses twos-complement integers and sign-magnitude floating point representations. – Ben Voigt Aug 02 '10 at 04:33
  • @Ben: Yes, as would have been obvious if you'd bothered to read the second sentence, I was talking about integers, not floating point. – Jerry Coffin Aug 02 '10 at 04:39
  • @Jerry: I understand that. But I don't want some computer engineering student to see this thread and say "I won't bother learning what how sign-magnitude arithmetic works, because no one uses it anyway". – Ben Voigt Aug 02 '10 at 05:26