指向未知或不完整结构的指针

这个问题是对问题概念的测试。 为什么将类型定义为指向C中未定义结构的指针是有效的?

我知道这不是一个有用的程序,请弃权说“你没有定义这个和那个”。 讨论是关于opaque类型的指针aritmethic。 很抱歉打扰了太多人,但无论如何答案都很有用。

这个程序:

struct st1 { int a,b; }; struct st2; typedef struct st2 *foo; typedef struct foo *bar; void main(void) { struct st1 *net=0; foo ft1=0; bar test=0; net++; ft1++; test++; } 

用gcc编译时给出以下内容:

 pc:~$ cc tmp2.c tmp2.c: In function 'main': tmp2.c:17:6: error: increment of pointer to unknown structure ft1++; ^ tmp2.c:17:3: error: arithmetic on pointer to an incomplete type ft1++; ^ tmp2.c:18:7: error: increment of pointer to unknown structure test++; ^ tmp2.c:18:3: error: arithmetic on pointer to an incomplete type test++; ^ 

我想更好地理解这里发生了什么,因为当不知道指针指向什么时,指针aritmethic有点困难…

您通过声明它已通知编译器您在程序中有struct st2 ,但尚未定义它。 那种承诺编译器的定义将在稍后出现。

但是你没有在任何地方定义它。

请阅读此处关于声明和定义之间的区别。

按照函数原型的思路思考。

喜欢

 void fun(int); 

你说一个函数fun返回void并取一个int位于某个地方。 如果您不在程序中调用此函数,则不会造成任何损害。

但如果你确实称它为,你必须在某处定义它,比如

 void fun(int a) { ... } 

这里struct的情况类似。 如果你没有使用struct st2 (和struct foo )类型的变量或它的typedef -ed名称,那么就不会有任何错误。

但是如果你确实使用它们,必须定义它们,以便编译器知道应该做什么。

鉴于代码

 struct st2; typedef struct st2 *foo; 

struct st2可以被认为是“不透明结构” ,而foo是指向不透明结构的指针。 每个维基百科:

在计算机科学中,不透明数据类型是一种数据类型,其具体数据结构未在接口中定义。 这会强制执行信息隐藏,因为只能通过调用有权访问缺少信息的子例程来操纵其值。 该类型的具体表示对其用户是隐藏的,并且可见的实现是不完整的。

没有结构细节,你已经注意到它不可能做指针算术。

您缺少struct st2的定义。 你只需要一个声明告诉编译器这样的结构存在,但你没有告诉编译器结构成员是什么,所以编译器不知道如何做任何取决于知道大小或成员的操作结构。 当你执行ft1++ ,你告诉编译器将ft1指针增加struct st2的大小,这是未知的。

同样的事情适用于struct foo

指向“opaque类型”的指针的主要用途仅仅是从库例程(或类似)例程接收它并将其传递给其他例程。 因此,不需要对这些类型执行算术运算。

例如,有人可能会调用一个例程,说“准备从这个文件中读取东西。 它将使用格式X格式化,子元素长度为Z,我将使用它们计算P,Q和R.“作为响应,例程设置一些缓冲区,准备一些表来帮助解析,并计算计算P,Q和R所需的一些数字。“该例程返回指向您的指针。

对你来说,那个指针是不透明的; 你不知道它指向的是什么结构。 对于例程,它是一个非常特定的结构,在库中定义并与其他库例程共享。

稍后,您调用另一个执行实际工作的例程,并将指针传递给它。 其他库例程知道结构的定义,因此它可以使用其中的所有内容。

这样做的一个优点是库的未来版本可以改变结构的定义。 由于您的程序永远不会看到定义,因此不能依赖它。 因此,如果库想要添加function或改变内部工作方式,它可以改变结构的定义。 然后您的源代码不需要重新编译。 当它与库的新版本链接时,新库将使用新结构。

所有这一切都始于对这个答案的回复的评论: 为什么在C中将类型定义为指向未定义结构的指针是有效的? 并且确实没有必要制造这样的混乱。 无论如何,我回答我的问题,以便更好地澄清并提供更多信息。 我不是C大师,所以我的术语可能不精确。

最初的问题是为什么声明指向不存在的结构的指针的C程序可以正确编译。 简而言之,因为这种方式可以使用不透明的类型,可以在不太了解它们的情况下使用它们(因此程序员不能摆弄它们的内容)。 这是一个很好的C技巧,特别是在图书馆中使用; C语言在标识符可见性方面并不出色,而且这种技巧在某种程度上克服了这种限制。

原始问题的答案之一表明,这些指针(不透明类型的指针)与其他指针并没有真正的不同。 这个陈述并不完全正确,我的评论(“指针运算怎么样?”)只是为了报警。

好吧,原始问题的答案是声明(通过typedef)指向未声明结构的指针并不是错误,并且声明具有该类型的变量也不是错误。 但是尝试以某种方式使用这种类型是错误的(那些需要知道该类型背后的真实数据的方式)。

老实说,C语言行为不是最大的一致性,而我想到的唯一原因是因为你可以声明不透明的类型。 这些opaque类型仅在单独的编译单元(尤其是库)的上下文中有用。 同样,C单独编译单元的方式特定于C,并不完美。

通过陈述“必须定义声明”,出现了一些微妙的错误思想。 我们想要不透明的数据吗? 然后不能完成不完整的声明。 因此,指向不透明数据的指针无法进行某些操作。

在本页顶部问题中发布的程序中,有一个typedef声明引用了一个完全不存在的结构(“struct foo”)。 这是另一点:可以让typedef引用不完整的结构,但是提到不存在的结构则更奇怪。 肯定有一个很好的理由:嘿,C是C.