摘要:在编译C文件的时候,有时候经常莫名其妙遇到错误提示:“数组元素的类型不完全错误”。本文主要解释错误原理和避免方法
char str[]; char str[10];当编译器碰到第一个声明时,认为str是一个不完全类型,碰到第二个声明时str就组合成完全类型了,如果编译器处理到程序文件的末尾仍然无法把str组合成一个完全类型,就会报错.
test.c:3: 错误:在‘str’中缺少数组大小
这个语法有什么用呢?为何不在第一次声明时就把str声明成完全类型?有些情况下这么做有一定的理由,比如第一个声明是写在头文件里的,第二个声明写在.c文件里,这样如果要改数组长度,只改.c文件就行了,头文件可以不用改。
不完全结构体的作用:
struct s { struct t *pt; }; struct t { struct s *ps; };struct s和struct t各有一个指针成员指向另一种类型。编译器从前到后依次处理,当看到struct s {struct t* pt; };时,认为struct t是一个不完全类型,pt是一个指向不完全类型的指针,尽管如此,这个指针却是完全类型,因为不管什么指针都占4个字节存储空间,这一点很明确。然后编译器又看到struct t {struct s *ps; };,这时struct t有了完整的定义,就组合成一个完全类型了,pt的类型就组合成一个指向完全类型的指针。由于struct s在前面有完整的定义,所以struct s *ps;也定义了一个指向完全类型的指针。
变量成员无法递归定义:
这样的类型定义是错误的:struct s { struct t ot; }; struct t { struct s os; };编译器看到struct s { struct t ot; };时,认为struct t是一个不完全类型,无法定义成员ot,因为不知道它该占几个字节。所以结构体中可以递归地定义指针成员,但不能递归地定义变量成员,你可以设想一下,假如允许递归地定义变量成员,struct s中有一个struct t,struct t中又有一个struct s,struct s又中有一个struct t,这就成了一个无穷递归的定义。也就是说,我们在定义一个变量的时候,一定要知道这个变量所占用存储空间的大小。
struct s { char data[6]; struct s* next; };当编译器处理到第一行struct s {时,认为struct s是一个不完全类型,当处理到第三行struct s *next;时,认为next是一个指向不完全类型的指针,当处理到第四行};时,struct s成了一个完全类型,next也成了一个指向完全类型的指针。类似这样的结构体是很多种数据结构的基本组成单元,如链表、二叉树等,我们将在后面详细介绍。下图示意了由几个struct s结构体组成的链表,这些结构体称为链表的节点(Node)。
...... extern struct _fstruct ps_fontinfo[]; ...... struct _fstruct { char *name; /* Postscript font name */ int xfontnum; /* template for locating X fonts */ };
上面这个错误是比较明显的,比较不明显的情况是:在头文件中声明了一个结构体数组,而这个结构体的定义在另外一个头文件中。
在global.h中,有这样的代码:#include "proc.h" extern struct proc proc_table[];在proc.h中,有如下的代码:
#include "global.h" struct proc{int a; int b};好,到这里还没有明显的错误,下面,我们新建C文件,proc.c
#include "proc.h" #include "global.h"这里,我们虽然proc在global.h的前面,但是由于proc.h之中包含global.h,所以,global.h的内容会在预处理阶段先被包含进来,这样就会比较隐晦的引发上面的错误。
如何解决这个问题:根源:通过良好的设计,避免头文件相互引用。如果实在无法避免这个情况,可以调整头文件的内容,比如将proc.h中内容调整为:
struct proc{int a; int b}; #include "global.h"也就是说,在头文件中,将没有依赖的部分提升到最前面。
C文件编译错误:数组、数据类型不完全,布布扣,bubuko.com
原文:http://blog.csdn.net/trochiluses/article/details/23088649