取消引用未初始化的指针以传递给 sizeof()

Dereferencing an uninitialized pointer to pass into sizeof()

在最近的 post 中,我意识到在分配结构变量时,传递取消引用的指针被认为是比将结构类型传递给 sizeof() 更好的做法。这基本上是因为前者比后者更能适应代码变化。

这表明,在下面的代码中,方法 1 被认为比 方法 2 更好。

typedef struct X_ {
    int x;
    int y;
    int z;
} X;

int main() {
    X* obj1 = malloc(sizeof(*obj1)); // ----> method 1
    X* obj2 = malloc(sizeof(X));     // ----> method 2
    return 0;
}

问题是,在方法 1 中取消引用 obj1 的有效性如何?在 malloc 内,obj1 仍然是 unconstructed/uninitialized 内存,这表明在 sizeof() 内发生的 obj1 取消引用不应该有效。

让我猜猜是什么让方法 1 有效。这是因为 sizeof() 是一个编译时操作,取消引用 obj1 被编译器翻译成 方法 2

请问有哪位能参考相关的C标准详细说明一下技术有效性吗?

操作数不是可变长度数组的 sizeof 表达式是非计算表达式。所以这个表达式

sizeof(*obj1)

格式正确。

来自 C 标准(6.5.3.4 sizeof 和 alignof 运算符)

2 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

关于你关于指定 malloc 参数的最佳方法的问题

X* obj1 = malloc(sizeof(*obj1)); // ----> method 1
X* obj2 = malloc(sizeof(X));     // ----> method 2

然后如果类型 X 在使用 malloc 时是可见的,就像在这种情况下

X* obj1 = malloc(sizeof(*obj1)); // ----> method 1

那么这种方法更可取。

但是,如果类型不可见,例如

obj1 = malloc(sizeof(*obj1)); // ----> method 1

然后我更喜欢明确指定类型

obj1 = malloc(sizeof( X ));

否则例如这个代码片段

p = malloc( *p );
q = malloc( *q );

没有为代码的 reader 提供足够的信息。 reader 需要前后滚动源代码才能找到 pq 的声明以确定它们的类型。

The question is, how valid is it to dereference obj1 in method 1?

100% 有效。不过,您可以在不带括号的情况下使用它,sizeof *obj1.

来自N1570 ISO/IEC 9899:201x §6.5.3.4 The sizeof and _Alignof operators

2 - 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.

事实上,可以说这是一种更可取的方法,原因是如果您出于某种原因更改了对象的类型,很容易忘记使用解除引用的方式也更改 sizeof 参数指针将避免这种潜在的无提示错误。