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++)!
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.
@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. :-)
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.
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.
@ Aaron – I don’t know why the value of i is 8 in the expression ‘int i = sizeof( ++c1 )’, thanks in advance.
@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).
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.