A recent code sample i saw:
#include <stdio.h>
#include <stdlib.h>
struct x {
int a;
int b;
};
int main(void) {
struct x *ptr = malloc(sizeof(*ptr));
return 0;
}
How does
sizeof(*ptr)
even work?How can a undefined pointer be dereferenced and be given to
sizeof()
and yield the correct size? (surely it should result in undefined behavior since its undefined)Lastly does the C standard define this sort of behavior at all? (maybe showing it is legal in C, i could not find anything)
CodePudding user response:
ptr
is not actually dereferenced here. The operand of the sizeof
operator, in this case the expression *ptr
, is looked at only for its type.
This is spelled out in section 6.5.3.4p2 of the C standard regarding the sizeof
operator:
The
sizeof
operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant
In this particular case, *ptr
is not evaluated but it is seen to have type struct x
, so sizeof(*ptr)
evaluates to a constant which is the size in bytes of struct x
.
CodePudding user response:
sizeof
is not a function call, it is an operator. It does not work on the value of ptr
, but its type. ptr
has been declared to be of type struct x*
and so the compiler knows that sizeof(*ptr)
is equivalent to sizeof(struct x)
.
CodePudding user response:
The sizeof
operator takes an expression or a parenthesized type as its argument. It does not evaluate its argument unless that argument is a variable length array. Either way, the size is determined from the type of the operand.
So, given a pointer int *p
, sizeof *p
yields the size of an int
since the expression *p
has type int
. There is no evaluation and hence no dereference here. Alternatively, you could use sizeof(int)
to find the size of an int
. In the first case the operand is the expression *p
, and in the second case the operand is the parenthesized type (int)
.
It may be worth commenting that struct x *ptr = malloc(sizeof(*ptr));
is a useful C idiom. The parentheses around *ptr
are not needed since *ptr
is an expression, not a type:
struct x *ptr = malloc(sizeof *ptr);
This construct is clear and easy to maintain when types change, e.g., when struct x
is no longer desired, but now struct y
is needed, there is only one thing to change:
struct y *ptr = malloc(sizeof *ptr);
After this one simple change ptr
is a pointer to struct y
, and the correct amount of memory has been allocated for one struct y
.