如果某个模块依赖于某个其他子模块,要么将其包含在其标题中,要么包含在其代码文件中,以及除了对主程序有贡献之外,模块是否也相互依赖?
下图示意性地说明了module1.h / .c需要子模块module4.h,而module2需要module3的情况。
每个头文件都有自己的typedef结构例:
typedef struct list * List;
和与头文件相关的源文件实现结构如:
struct list {
unsigned length;
char * value;
};
我在头文件中有另一个结构:
typedef enum {START, END, MIDDLE, COMMENTS, CONDITIONS} TypeListBal;
typedef struct bal * Bal;
和源文件:
struct bal {
TypeListBal type;
List name; // Name of the bal
List attributes[]; // Array of type struct List
};
我今晚读了很多,而且我对一件事情不太确定。如果我只是在我的案例中包含我需要的源文件中的头文件,我在bal.c中包含list.h,因为我的bal.c得到了一个结构定义,作为List类型的成员
为了使它工作,我是否必须在我的所有模块中放置特定的#INCLUDE,或者在编译时完成工作?
我的意思是在make makefile中,拥有我的bal.o对象,它看起来像:
bal.o: list.o bal.c bal.h
$(CC) -g -W -Wall -c list.o bal.c bal.h
因此,只要makefile尝试编译bal.o,编译器就会看到所有依赖项,并且能够编译所有内容。
这就是我的理解方式但是当我尝试这个时,我得到了:
error: dereferencing pointer to incomplete type
我猜它是因为在我的bal.c文件中,我声明了struct List类型的变量,并且编译器没有关于struct List的任何想法导致定义struct list的列表在list.c文件中。
所以问题又是: 如何连接所有内容以使其正常工作?
答案 0 :(得分:1)
您的标头文件已损坏。这是一个不完整的类型:
typedef struct bal * Bal;
它需要struct
声明才能完成。那也应该在头文件中。如果在C代码中你说*Bal
没有完整的类型,编译器就会放弃,因为它没有关于这个表达式的含义的任何信息,即结构的字段。
您正在显示的依赖关系图应该完全没问题。您希望使用防护来确保头文件仅包含一次。然后你可以包含一个来自另一个的头,而C预处理器将会#34;正好工作"只要没有循环依赖。在您的情况下,标题为例如模块4看起来像:
// module4.h
#ifndef MODULE_4_H_INCLUDED
#define MODULE_4_H_INCLUDED
#include "module1.h"
// all public type declarations for module 4 types
#endif // MODULE_4_H_INCLUDED
使用自己的守护定义使所有标题(包括module1.h)相似。然后模块4代码:
// module4.c
#include "module4.h"
// Use module 4 types.
通常,如果您需要某个.c
文件中的头文件给出的类型,即使它被头文件之间的依赖项包含在内,也要包括它。警卫通常会确保没有裁员。
此外,您对make依赖关系的想法是错误的。例如。要成功汇编module4.c
以获取module4.o
,您需要(当然)module4.c
,module4.h
和module1.h
。这些是构建依赖项。因此规则将是:
module4.o : module4.c module4.h module1.h
$(CC) -g -W -Wall -c module4.c
但你不应该写这样的具体规则。 Make具有易于使用的内置函数和一般规则。您可以使用gcc
本身生成头文件依赖项,而不是手动跟踪它们(这可能会导致各种灾难)。请参阅the -M option。
答案 1 :(得分:0)
如果编译器只看到:
typedef struct list * List;
在包含的文件中,当编译器编译特定的* .c文件时,在其他地方没有struct list
的定义,如果* .c文件中的代码将List
指针取消引用访问List
结构的成员,将报告错误,因为尚未定义struct list
。
仅仅因为struct list
的定义存在于某个其他文件中,在同一目录中的其他位置,单独编译,并不意味着编译器在编译时会知道它是什么这个文件。
单个* .c文件的编译是与编译任何其他* .c文件完全不同的过程,编译器只会看到明确{{1}的结构,函数和其他内容的定义。在编译那个特定文件时,直接在#include
文件中声明。