鉴于 p 是指向不完整类型的指针,&*p 是否有效 C?
以下示例是 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 theregister
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,我认为这是一个错误。即使是不完整类型的左值,例如
*j
,似乎也被允许,具体取决于上下文:基本上,只要您不使用需要了解 struct 结构的左值执行任何操作,就应该可以工作。因此,如果您不访问该对象或询问其大小,这是合法的。
Yes, I think it is a bug. Even lvalues of incomplete types, so
*j
, seem to be allowed depending on the context: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.C99 标准 (ISO/IEC 9899:1999) 描述了以下行为:
这意味着
&*j
相当于j
。然而,
j
应该是一个指向对象的指针,而且它只是一个指向不完整类型的指针,正如 GCC 4.4.5 所说。请注意,它区分对象类型和不完整类型;这在标准中经常出现。
因此,问题中的这一观察是不正确的:
变量
j
不是指向对象的指针;它是一个指向不完整类型的指针,它不是一个对象。The C99 standard (ISO/IEC 9899:1999) describes the behaviour:
This means that
&*j
is equivalent toj
.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.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:
The variable
j
is not a pointer to an object; it is a pointer to an incomplete type, which is not an object.是的。 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.