C文件编译错误:数组、数据类型不完全

摘要:在编译C文件的时候,有时候经常莫名其妙遇到错误提示:“数组元素的类型不完全错误”。本文主要解释错误原理和避免方法


1.什么是不完全类型

        具有不完全类型的变量可以通过多次声明组合成一个完全类型,比如数组str声明两次:
char str[];
char str[10];
当编译器碰到第一个声明时,认为str是一个不完全类型,碰到第二个声明时str就组合成完全类型了,如果编译器处理到程序文件的末尾仍然无法把str组合成一个完全类型,就会报错.
test.c: 在函数‘main’中:

test.c:3: 错误:在‘str’中缺少数组大小


2.不完全类型的作用

    这个语法有什么用呢?为何不在第一次声明时就把str声明成完全类型?有些情况下这么做有一定的理由,比如第一个声明是写在头文件里的,第二个声明写在.c文件里,这样如果要改数组长度,只改.c文件就行了,头文件可以不用改。


3.不完全类型原理与举例

    不完全结构体的作用:

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;也定义了一个指向完全类型的指针。

 4.不完全类型使用陷阱

     变量成员无法递归定义:

这样的类型定义是错误的:
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)。


5.一些常见错误

    一个常见的错误就是:类型的先使用后声明:
...... 
extern struct _fstruct	ps_fontinfo[]; 
...... 
struct _fstruct { 
char	 *name;	/* Postscript font name */ 
int	 xfontnum;	/* template for locating X fonts */ 
}; 

注意:ps_fontinfo是一个变量,是先声明后使用的。但是struct _fstruct类型,是先使用后声明的。


6.更加隐晦的高级错误与解决方法:

    上面这个错误是比较明显的,比较不明显的情况是:在头文件中声明了一个结构体数组,而这个结构体的定义在另外一个头文件中。

在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"
    也就是说,在头文件中,将没有依赖的部分提升到最前面。

你可能感兴趣的:(头文件相互引用,数组类型不完全错误,Gcc编译错误)