我最近看到的一个代码示例:
#include <stdio.h>
#include <stdlib.h>
struct x {
int a;
int b;
};
int main(void) {
struct x *ptr = malloc(sizeof(*ptr));
return 0;
}
sizeof(*ptr)
是如何工作的?如何取消引用未定义的指针并将其赋予
sizeof()
并产生正确的大小?(当然,它应该导致未定义的行为,因为它是未定义的(最后,C标准是否定义了这种行为?(可能表明它在C中是合法的,我找不到任何东西(
ptr
在这里实际上没有被取消引用。sizeof
运算符的操作数,在本例中为表达式*ptr
,只查看其类型。
这在关于sizeof
操作员的C标准第6.5.3.4p2节中有详细说明:
sizeof
运算符产生其操作数的大小(以字节为单位(可以是表达式或类型的带括号的名称。尺寸为根据操作数的类型确定。结果是一个整数。如果操作数的类型是可变长度数组类型,操作数评估否则,不计算操作数,结果是一个整数常量
在这种特殊情况下,*ptr
没有被求值,但它被视为具有类型struct x
,因此sizeof(*ptr)
求值为一个常量,该常量是struct x
的字节大小。
sizeof
不是函数调用,而是运算符。它不处理ptr
的值,而是处理其类型。ptr
已被声明为struct x*
类型,因此编译器知道sizeof(*ptr)
等价于sizeof(struct x)
。
演示。
sizeof
运算符将表达式或带括号的类型作为其参数。它不会计算其参数,除非该参数是可变长度数组。无论哪种方式,大小都由操作数的类型决定。
因此,给定指针int *p
,sizeof *p
产生int
的大小,因为表达式*p
具有类型int
。这里没有评估,因此没有取消引用。或者,您可以使用sizeof(int)
来查找int
的大小。在第一种情况下,操作数是表达式*p
,在第二种情况下操作数是带括号的类型(int)
。
值得注意的是,struct x *ptr = malloc(sizeof(*ptr));
是一个有用的C习语。不需要*ptr
周围的括号,因为*ptr
是一个表达式,而不是类型:
struct x *ptr = malloc(sizeof *ptr);
当类型发生变化时,这种结构清晰且易于维护,例如,当不再需要struct x
,但现在需要struct y
时,只有一件事需要改变:
struct y *ptr = malloc(sizeof *ptr);
在这一个简单的改变之后,ptr
是指向struct y
的指针,并且已经为一个struct y
分配了正确的内存量。