40
#include <stdio.h>
int main(void)
{
    if (sizeof(int) > -1)
        printf("True");
    else
        printf("False");
}

It prints False. Why doesn't sizeof() return a value in the if?

Raja Narayan
  • 595
  • 5
  • 14

5 Answers5

55
  1. sizeof is not a function, it's an operator. The parentheses are not part of the operator's name.
  2. It's failing because the value generated has the unsigned type size_t, which causes "the usual arithmetic conversions" in which -1 is converted to unsigned, in which case it's a very large number.

Basically you're comparing 4 > 0xffffffffu, or something close to that at least. See this question for details.

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606
  • 4
    Strictly speaking, there is no integer promotion here, but rather _balancing_ (formally called "_the usual arithmetic conversions_"). – Lundin Jun 25 '13 at 09:41
  • 11
    converting `-1` to an unsigned integer type always yields the maximum value, even if the representation isn't two's complement – Christoph Jun 25 '13 at 09:44
  • 7
    Your first point is true, but irrelevant. It would have been the same with a function returning `size_t`. – ugoren Jun 25 '13 at 10:54
  • Just for nit-pickings sake: if `sizeof sizeof 1 < sizeof 1`, `sizeof(int)>-1` would be `true`. – Deduplicator Sep 28 '14 at 23:01
  • @ugoren Yes, of course. I just strive to, uh, teach people this fact, since it's quite annoying that so many people who program C seem to misunderstand it. Probably sign of my hubris. – unwind Nov 12 '14 at 08:12
24

Unsigned and signed integer promotion (rather "usual arithmetic conversions", to be more precise). sizeof yields a value of type size_t, and when compared to an unsigned value (which size_t is), -1 is promoted to that type, and overflows and becomes huge.

Unsigned integer overflow has well-defined behavior and is to be taken as modulo 2 ^ width, where width is the number of bits in the particular unsigned integer type. So, if you have a 32-bit wide size_t and int, for example, your comparison will be equivalent with

if (4 > 4294967295u)

which is obviously false.

  • Great answer, but wouldn't it be underflowing rather than overflowing? – C0deH4cker Jun 25 '13 at 15:13
  • 1
    @C0deH4cker Well, it all depends on how you interpret it :) I prefer "underflow" to be used for floating-point numbers, when some `x < epsilon` number becomes zero. "Overflow" is easier to grasp here if you think of the phenomenon in terms of modulo arithmetic (that's how it's defined anyway). –  Jun 25 '13 at 15:55
  • Ah okay, this answer (http://programmers.stackexchange.com/questions/32893/is-int-min-1-an-underflow-or-overflow) explains it and also why I was confused. – C0deH4cker Jun 26 '13 at 15:57
13
  • The operands of the > operator in the if statement are sizeof(int) and -1.
  • sizeof(int) is of type size_t, which is guaranteed to be an unsigned integer. In practice, size_t will most likely be at least as big as unsigned int on any system out there.
  • -1 is of type int, which is equivalent to signed int.
  • No integer promotions occur, as both operands are of large enough integer types.
  • Then the two operands are balanced according to a C rule formally called the usual arithmetic conversions.

These state (C11 6.3.1.8):

...

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.

  • The latter of the above will happen, since a (signed) int cannot fit all values of a size_t.
  • Thus -1 is converted to an unsigned integer. In practice, size_t is most likely equivalent to either unsigned int or unsigned long. Whatever happens when you store -1 in such a variable is implementation-defined behavior.
  • On a two's complement computer (99.9% of all computers in the world), -1 will be interpreted as 0xFFFFFFFF (the number of FF depends on the size of an int on the given system).
  • 4 > 0xFFFFFFFF evaluates to false.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 8
    "Whatever happens when you store -1 in such a variable is implementation-defined behavior." Umm, the only implementation-dependent thing here is the width of `size_t`. converting `-1` to an unsigned type is mandated to result in the maximum value of that type by the standard. – Daniel Fischer Jun 25 '13 at 09:57
  • @DanielFischer What I meant with that, is that the manner of signed integer behavior is impl.defined. C allows two's complement, one's complement and so on. – Lundin Jun 25 '13 at 14:15
  • Where "and so on" expands to "signed magintude" or "sign and magnitude", depending on which name you prefer. So whether the conversion is just a truncation/reinterpretation/sign-extension or changes the bit-pattern in a different way is implementation-defined, yes. But that's pretty irrelevant, isn't it? The important thing is the result. – Daniel Fischer Jun 25 '13 at 14:22
  • @DanielFischer The result depends on the manner of signedness. -1 would give you 0xFFFFFFFE. Since I used 0xFFFFFFFF in my example, I wanted to point out that strictly speaking, -1 is not guaranteed to be 0xFFFFFFFF. Otherwise someone would post a comment and whine about that, since C allows obscure signedness formats as well. – Lundin Jun 25 '13 at 14:35
  • 3
    While the bit pattern of `-1` need not be `0xFF..F`, the result of the conversion of `-1` (from a signed integer type) to an unsigned integer type always (well, unless the width is not a multiple of 4) has the bit pattern `0xFF...F`. That's mandated by the standard [modulo the as-if rule]. – Daniel Fischer Jun 25 '13 at 14:41
  • Sorry for replying to an old answer - I came here from a question that was marked as a duplicate of this question. I cannot find anything in the standard that guarantees that `size_t` will be at least as big as `unsigned int`. I think it is only guaranteed to be as big as `unsigned short`. So it is technically possible for a bizarre, but legal implementation of C to evaluate `sizeof(int) > -1` as `1` instead of the more typical `0`. – Ian Abbott Aug 18 '17 at 14:20
  • @IanAbbott Yeah, I actually believe that's true, at least in theory. In practice, it would be a very weird system to make `size_t` smaller than the default `int` type. But I can fix the post. – Lundin Aug 18 '17 at 14:28
  • @Lundin. Yes, it would be bizarre. I made a mistake too. It's not guaranteed to be as bit as `unsigned short`. It's only guaranteed that it's maximum value is at least 65535. – Ian Abbott Aug 18 '17 at 14:31
2

Sizeof is an operator that results in an unsigned long int. Hence, when you compare unsigned long int with -1, which is stored as 0xffffffff (size of int is 4 bytes).

-1 is signed integer by default. But, in comparison between signed int and unsigned int, the compiler goes with implicit typecasting of signed int to unsigned int. This results in unsigned -1 to be approximately equal to 4.6giga value.

Hence, the output is false.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
surendra nath
  • 339
  • 2
  • 15
1

Just test this and see for yourself

#include <stdio.h>
main() {
    unsigned int a=4;
    int b = -1;
    //this is what you're doing
    printf("%u vs %u\n", a, (unsigned int)b);
    //this is what you want to do instead
    printf("%d vs %d\n", (int)a, b);
}