考虑到p是指向不完整类型的指针,& * p是否有效?

时间:2011-08-04 06:54:07

标签: c pointers language-lawyer incomplete-type

以下示例是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中的缺陷吗?

3 个答案:

答案 0 :(得分:6)

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

  

6.3.2.1 ... 左值是一个带有对象类型或表达式的表达式   除void之外的不完整类型

基本上,只要你不对需要了解struct结构的左值做任何事情,这应该有效。因此,如果您不访问该对象或询问其大小,这是合法的。

答案 1 :(得分:3)

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

  

§6.5.3.2地址和间接运算符

     

一元&运算符返回其操作数的地址。如果操作数的类型为''type'',   结果有''指向类型''的类型。如果操作数是一元*运算符的结果,   无论是运营商还是&运算符被评估,结果就像两者都是   省略,除了对运算符的约束仍然适用且结果不是a   左值。

这意味着&*j相当于j

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

  

§6.3.2.3指针

     

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

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

所以,问题中的这个观察是不正确的:

  

这两方面都非常满意,

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


  

§6.2.5类型

     

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

答案 2 :(得分:2)

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

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

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