sizeof() 如何与取消引用一起工作?

How does sizeof() work with a dereference?

提问人:professional pro 提问时间:9/9/2022 更新时间:9/9/2022 访问量:322

问:

我最近看到的代码示例:

#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 中显示它是合法的,我找不到任何东西)

c 指针 malloc sizeof

评论

1赞 Pablo 9/9/2022
siezof不是一个函数,它是一个在编译时计算的运算符。编译器知道这是指向 的指针,因此将是一个 .编译器从结构定义中知道结构的大小。ptrstruct x*ptrstruct x
0赞 Paul Lynch 9/9/2022
在这里,混乱是可以理解的。sizeof(*ptr) 看起来像一个函数调用(当使用 parens 时),但它实际上是一个编译时运算符。PTR 未被取消引用;*ptr 用于指示指针处的数据类型。
0赞 Dúthomhas 9/9/2022
顺便说一句,没有“取消引用”这样的东西。指针可以被取消引用,也就是说,从引用对象的值转换为引用的对象值本身。
1赞 yano 9/9/2022
到目前为止,还有一件事没有说,OP中显示的方法是确定要传递的大小的首选方法,原因是维护较少。如果有一天类型从 更改为 怎么办?如果你这样做了,那么你也需要把它改成。但是,通过这样做,不需要进行任何更改,因为现在是一种类型,因此您会自动获得该更改,并且始终将正确的大小传递给 。mallocptrstruct x*struct y*malloc(sizeof(struct x))sizeof(struct y)sizeof(*ptr)*ptrstruct ymalloc

答:

2赞 Schwern 9/9/2022 #1

sizeof 不是函数调用,而是运算符。它不适用于 的值,但不适用于其类型。 已声明为 类型,因此编译器知道它等价于 .ptrptrstruct x*sizeof(*ptr)sizeof(struct x)

演示

1赞 ad absurdum 9/9/2022 #2

运算符采用表达式或带括号的类型作为其参数。除非该参数是可变长度数组,否则它不会计算其参数。无论哪种方式,大小都是由操作数的类型确定的。sizeof

因此,给定一个指针,由于表达式的类型为 。这里没有评估,因此没有取消引用。或者,您可以使用 来查找 .在第一种情况下,操作数是表达式,在第二种情况下,操作数是带括号的类型。int *psizeof *pint*pintsizeof(int)int*p(int)

可能值得评论,这是一个有用的 C 习语。不需要括号,因为这是一个表达式,而不是一个类型:struct x *ptr = malloc(sizeof(*ptr));*ptr*ptr

struct x *ptr = malloc(sizeof *ptr);

当类型发生变化时,这种结构是清晰且易于维护的,例如,当不再需要时,但现在需要时,只有一件事要改变:struct xstruct y

struct y *ptr = malloc(sizeof *ptr);

在此之后,一个简单的更改是指向 的指针,并且已为一个 分配了正确的内存量。ptrstruct ystruct y

3赞 dbush 9/9/2022 #3

ptr实际上并没有在这里取消引用。运算符的操作数,在本例中为表达式 ,仅查看其类型。sizeof*ptr

这在 C 标准第 6.5.3.4p2 节中关于运算符的详细说明:sizeof

运算符生成其操作数的大小(以字节为单位),其中 可以是表达式或带括号的类型名称。尺寸是 根据操作数的类型确定。结果是一个整数。如果 操作数的类型是可变长度数组类型,即操作数 被评估;否则,不会计算操作数和结果 是一个整数常量sizeof

在这种特殊情况下,不计算,但看到它具有类型,因此计算为一个常量,其大小为 字节 。*ptrstruct xsizeof(*ptr)struct x