We all know that dereferencing an null pointer or a pointer to unallocated memory invokes undefined behaviour.
But what is the rule when used within an expression passed to sizeof?
For example:
int *ptr = 0;
int size = sizeof(*ptr);
Is this also undefined?
In most cases, you will find that
sizeof(*x)does not actually evaluate*xat all. And, since it’s the evaluation (de-referencing) of a pointer that invokes undefined behaviour, you’ll find it’s mostly okay. The C11 standard has this to say in6.5.3.4. The sizeof operator /2(my emphasis in all these quotes):This is identical wording to the same section in C99. C89 had slightly different wording because, of course, there were no VLAs at that point. From
3.3.3.4. The sizeof operator:So, in C, for all non-VLAs, no dereferencing takes place and the statement is well defined. If the type of
*xis a VLA, that’s considered an execution-phasesizeof, something that needs to be worked out while the code is running – all others can be calculated at compile time. Ifxitself is the VLA, it’s the same as the other cases, no evaluation takes place when using*xas an argument tosizeof().C++ has (as expected, since it’s a different language) slightly different rules, as shown in the various iterations of the standard:
First,
C++03 5.3.3. Sizeof /1:In,
C++11 5.3.3. Sizeof /1, you’ll find slightly different wording but the same effect:C++11 5. Expressions /7(the above mentioned clause 5) defines the term “unevaluated operand” as perhaps one of the most useless, redundant phrases I’ve read for a while, but I don’t know what was going through the mind of the ISO people when they wrote it:C++14/17 have the same wording as C++11 but not necessarily in the same sections, as stuff was added before the relevant parts. They’re in
5.3.3. Sizeof /1and5. Expressions /8for C++14 and8.3.3. Sizeof /1and8. Expressions /8for C++17.So, in C++, evaluation of
*xinsizeof(*x)never takes place, so it’s well defined, provided you follow all the other rules like providing a complete type, for example. But, the bottom line is that no dereferencing is done, which means it does not cause a problem.You can actually see this non-evaluation in the following program:
You might think that the final line would output something vastly different to
42(774, based on my rough calculations) becausexhas been changed quite a bit. But that is not actually the case since it’s only the type of the expression insizeofthat matters here, and the type boils down to whatever typexis.What you do see (other than the possibility of different pointer sizes on lines other than the first and last) is: