Why is this happening with the sizeof operator whe

2019-01-01 14:10发布

问题:

This question already has an answer here:

  • sizeof() operator in if-statement 5 answers

What\'s really happening here? The output now is \"False\":

#include <stdio.h>

int main()
{
     if (sizeof(int) > any_negative_integer)
         printf(\"True\");
     else
         printf(\"False\");
     return 0;
}

If I change it to:

if (sizeof(int) < any_negative_integer)

the output is \"True\".

Update: the same question has already been asked, I could not find it before asking.

回答1:

sizeof returns size_t which is unsigned and so -1 is being converted to a very large unsigned number. Using the right warning level would have helped here, clang with the -Wconversion or -Weverything(note this is not for production use) flags warns us:

warning: implicit conversion changes signedness: \'int\' to \'unsigned long\' [-Wsign-conversion]
   if (sizeof(int) > -1)
                   ~ ^~

For gcc you receive a similar warning using the -Wextra flag:

warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    if (sizeof(int) > -1)
                    ^

For reference, we know size_t is unsigned from the draft C99 standard section 7.17 Common definitions which says:

 size_t

which is the unsigned integer type of the result of the sizeof operator;[...]

Note, it does not specify anything else about the type, in my specific case it happens to be unsigned long but it does not have to be.

The conversion of -1 is due to the usual arithmetic conversion covered in section 6.3.1.8 Usual arithmetic conversions which says:

[...]

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.

So the only time -1 would not be converted to an unsigned value would be if int could represent all the values of size_t, which is not the case here.

Why -1 ends up being a large unsigned value, actually it ends up being being the max value of the unsigned type is due to section 6.3.1.3 Signed and unsigned integers which says:

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.49)

So we end up with:

-1 + (UMAX + 1)

which is:

UMAX

and thus end up with:

if (sizeof(int) > UMAX )


回答2:

Because sizeof() returns a size_t, an unsigned type. Comparing signed and unsigned types can give surprising results due to implicit casting before the comparison.