Interesting Note About the sizeof Operator

The expression used in a sizeof operator is an unevaluated expression in C and C++. This can make for some surprising situations if you are unaware of it. For instance:

#include <stdio.h>

int main( void ) {
  int a = 12;
  int b = sizeof( ++a );
  printf( "%d\n", a );
  return 0;
}

This code will print 12 instead of 13 because the expression ++a is unevaluated.

So what does it mean for an expression to be unevaluated? Basically, it means that the expression is used at compile time only as a way to determine a type, which is then used to evaluate the result of the sizeof operator. So in the above example, a’s type is determined, and the resulting type for ++ is determined, but no code is generated to execute the ++.

Here’s an abusive example that demonstrates this:

#include <stdio.h>

class c {
public:
  double operator++();
};

int main(int argc, char *argv[]){
  c c1;
  int i = sizeof( ++c1 );
  int j = sizeof( c1 );
  ::printf( "%d, %d\n", i, j );
  return 0;
}

If you run this code, you will see 8, 1 printed and will not get a link error (because of the failure to define operator++)!

This entry was posted in C/C++ and tagged , . Bookmark the permalink.

7 Responses to Interesting Note About the sizeof Operator

  1. Dan says:

    I recently saw an example where:

    sizeof(2500000000) = 8

    yet

    sizeof(1250000000 * 2) = 4

    Why?

    2,500,000,000 can’t find into a (signed, 32-bit) int, so it becomes a long int (8 bytes on most architectures). But 1,250,000,000 will fit into a (32-bit) signed int, and so will 2… thus the resulting expression is an int, which is 4 bytes on most architectures. Tricky.

  2. Aaron Ballman says:

    @Dan — yup, you’re exactly right. The two values are both int, and the result of operator+ is going to be an int because of that. The constant expression, even though it could be folded into a final number, is never evaluated and so you wind up with sizeof(int). That’s another tricky one. :-)

  3. Ofek Shilon says:

    IIUC, even if 1250000000 * 2 *was* evaluated, the sizeof the result would still be 4. Without some explicit casting, the multiplication of two ints gives an int.

  4. Aaron Ballman says:

    One thing I should note: it’s unevaluated in C *except* if the expression involves a VLA.

    #include <stdio.h>

    int main(void) {
      size_t Count = 10;
      size_t Size = sizeof(int[Count++]);
      printf("%zu, %zu", Size, Count);
    }

    Will print 40, 11 because the VLA winds up forcing the evaluation of the expression within the sizeof operator.

  5. Hong Zhiyi says:

    @ Aaron – I don’t know why the value of i is 8 in the expression ‘int i = sizeof( ++c1 )’, thanks in advance.

  6. Aaron Ballman says:

    @Hong — The value is 8 because the ++ operator is a function call that is looked up on the c class, and the return type of c::operator++() is double (and sizeof(double) == 8).

  7. Tomasz Stanislawski says:

    The really fun part are VLA objects. For example:

    “`
    int main(void) {
    const int n = 12;
    int A[n][n];
    int m = 0;
    sizeof (A[m++]);
    printf(“%d”, m); // 1 in C, 0 in C++
    }
    “`

    The operand of `A` is evaluated causing `m` to be increment to 1. This does not happen in C++ because `n` is a constant so `int[n]` is not a VLA.

    IMO, the rules for evaluation of operands of `sizeof` are defective. It should require only evaluation of “size expressions”. It will make C and C++ behave more or less the same and would eliminate potential UBs in code like:
    “`
    int (*arr)[n] = malloc(sizeof *arr);
    “`

    where `*a` is evaluated while `a` is not initialized yet.

Leave a Reply

Your email address will not be published. Required fields are marked *