鉴于 p 是指向不完整类型的指针,&*p 是否有效 C?

发布于 2024-11-27 23:45:26 字数 962 浏览 4 评论 0原文

以下示例是 C 语言中有效的完整翻译单元吗?

struct foo;

struct foo *bar(struct foo *j)
{
    return &*j;
}

struct foo 是一个不完整类型,但我在 C 标准中找不到明确禁止取消引用不完整类型的规定。特别是,§6.5.3.2 说:

一元&运算符产生其操作数的地址。如果 操作数的类型为“type”,结果的类型为“指向类型的指针”。如果 操作数是一元 * 运算符的结果,两者都不是 运算符或 & 运算符均被求值,结果就像 两者都被省略,除了对运营商的限制仍然存在 应用并且结果不是左值。

结果不是左值这一事实没有密切关系——返回值不一定如此。 * 运算符的约束很简单:

一元 * 运算符的操作数应为指针类型。

& 运算符上是:

一元 & 运算符的操作数应为函数 指示符、[] 或一元 * 运算符的结果或左值 指定一个不是位域且未声明的对象 使用 register 存储类说明符。

这两个条件在这里都得到了满足,因此结果应该等同于 return j;

但是,gcc 4.4.5 不编译此代码。相反,它会给出以下错误:

y.c:5: error: dereferencing pointer to incomplete type

这是 gcc 中的缺陷吗?

Is the following example a valid complete translation unit in C?

struct foo;

struct foo *bar(struct foo *j)
{
    return &*j;
}

struct foo is an incomplete type, but I cannot find an explicit prohibition of dereferencing an incomplete type in the C standard. In particular, §6.5.3.2 says:

The unary & operator yields the address of its operand. If the
operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If
the operand is the result of a unary * operator, neither that
operator nor the & operator is evaluated and the result is as if
both were omitted, except that the constraints on the operators still
apply and the result is not an lvalue.

The fact that the result is not an lvalue is not germane - return values need not be. The constraints on the * operator are simply:

The operand of the unary * operator shall have pointer type.

and on the & operator are:

The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue
that designates an object that is not a bit-field and is not declared
with the register storage-class specifier.

Both of which are trivially satisfied here, so the result should be equivalent to just return j;.

However, gcc 4.4.5 does not compile this code. It instead gives the following error:

y.c:5: error: dereferencing pointer to incomplete type

Is this a defect in gcc?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦一生花开无言 2024-12-04 23:45:26

是的,我认为这是一个错误。即使是不完整类型的左值,例如 *j,似乎也被允许,具体取决于上下文:

6.3.2.1 ... 左值是具有对象类型或
除 void 之外的不完整类型

基本上,只要您不使用需要了解 struct 结构的左值执行任何操作,就应该可以工作。因此,如果您不访问该对象或询问其大小,这是合法的。

Yes, I think it is a bug. Even lvalues of incomplete types, so *j, seem to be allowed depending on the context:

6.3.2.1 ... An lvalue is an expression with an object type or an
incomplete type other than void

Basically this should work as long as you don't do anything with such an lvalue that needs to know about the structure of the struct. So if you don't access the object or ask about its size, this is legal.

嘦怹 2024-12-04 23:45:26

C99 标准 (ISO/IEC 9899:1999) 描述了以下行为:

§6.5.3.2 地址和间接运算符

一元 &运算符返回其操作数的地址。如果操作数的类型为“type”,
结果的类型为“指向类型的指针”。如果操作数是一元 * 运算符的结果,
既不是该运算符也不是 &运算符被求值,结果就好像两者都是
省略,除了对运算符的约束仍然适用并且结果不是
左值。

这意味着 &*j 相当于 j

然而,j 应该是一个指向对象的指针,而且它只是一个指向不完整类型的指针,正如 GCC 4.4.5 所说。

§6.3.2.3 指针

指向 void 的指针可以转换为指向任何不完整或对象的指针或从指向任何不完整或对象的指针转换
类型。指向任何不完整或对象类型的指针可以转换为指向 void 的指针
然后再回来;结果应等于原始指针。

请注意,它区分对象类型和不完整类型;这在标准中经常出现。

因此,问题中的这一观察是不正确的:

这两者在这里都得到了满足,

变量j不是指向对象的指针;它是一个指向不完整类型的指针,它不是一个对象。


§6.2.5 类型

[...] 类型
分为对象类型(完全描述对象的类型)、函数类型(类型
描述函数)和不完整类型(描述对象但缺乏
确定其大小所需的信息)。

The C99 standard (ISO/IEC 9899:1999) describes the behaviour:

§6.5.3.2 Address and indirection operators

The unary & operator returns the address of its operand. If the operand has type ‘‘type’’,
the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator,
neither that operator nor the & operator is evaluated and the result is as if both were
omitted, except that the constraints on the operators still apply and the result is not an
lvalue.

This means that &*j is equivalent to j.

However, j is supposed to be a pointer to an object, and it is only a pointer to an incomplete type, as GCC 4.4.5 says.

§6.3.2.3 Pointers

A pointer to void may be converted to or from a pointer to any incomplete or object
type. A pointer to any incomplete or object type may be converted to a pointer to void
and back again; the result shall compare equal to the original pointer.

Note that it distinguishes between an object type and an incomplete type; this occurs frequently in the standard.

So, this observation in the question is incorrect:

Both of which are trivially satisfied here,

The variable j is not a pointer to an object; it is a pointer to an incomplete type, which is not an object.


§6.2.5 Types

[...] Types
are partitioned into object types (types that fully describe objects), function types (types
that describe functions), and incomplete types (types that describe objects but lack
information needed to determine their sizes).

葬シ愛 2024-12-04 23:45:26

是的。 C 中的指针通常具有相同的大小(在某些嵌入式系统上,它们可以不同)。这意味着即使类型是“未知”,编译器也可以为此生成正确的汇编代码。

您可以使用这种方法向外部完全隐藏内部数据结构。使用typedef声明指向结构的指针,并且仅在内部头文件(即不属于公共API的文件)中声明该结构。

gcc 4.4.5 抱怨的原因就是:如果您在实现之外使用指向不完整类型的指针,它应该可以工作。但代码是实现的一部分,在这里,您可能希望拥有完整的类型。

Yes. Pointers in C usually have the same size (on some embedded systems, they can be different). This means the compiler can generate the correct assembler code for this even though the type is "unknown".

You can use this approach to completely hide the internal data structure to the outside. Use a typedef to declare a pointer to a structure and only declare the structure in your internal header files (i.e. the files which are not part of your public API).

The reason why gcc 4.4.5 complains is just that: If you use pointers to the incomplete type outside of the implementation, it should work. But the code is part of the implementation and here, you probably want to have the complete type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文