问题描述
我有几个 C 源文件和头文件,每个 ADT 都有一个 .h
文件。
其中之一称为锦标赛。当我尝试在 tournament.h
内为锦标赛分配内存时没有问题,但是当我在不同的 c 文件中执行此操作时,它给了我以下错误
“不允许不完整的类型”
这是在锦标赛.h中定义锦标赛的方式
typedef struct tournament_t *Tournament;
ps:有人说 typedef 一个结构体是一件坏事,但我必须这样做,因为老师们想要它。
这就是 tournament.c
中的情况,我对此没有任何问题
struct tournament_t
{
//fields
};
Tournament tournamentCreate()
{
Tournament new=malloc(sizeof(*new));
if(!new)
{
return NULL;
}
//I don't get any error here
}
但是,在名为 chess.c
的文件中,会发生以下情况:
#include "tournament.h"
static Tournament copyTournament(Tournament tournament)
{
if (!tournament) {
return NULL;
}
Tournament copy = malloc(sizeof(*copy));//here I get the error
if (!copy)
{
return NULL;
}
}
PS:最后一个函数必须是 static
,因为教师又希望它是。
如果您需要更多信息来解决它,请告诉我。
解决方法
typedef struct tournament_t *Tournament;
用作结构的前向声明。此时在头文件中,编译器不知道该结构的内容。这意味着您需要在别处编写结构体定义,否则结构体将重命名为 unknown - 一个不完整的类型。
然后将结构体定义放置在锦标赛.c 中。这意味着结构内容现在对翻译单元内的编译器可见。翻译单位表示 .c 文件及其包含的所有标题。
这反过来意味着您可以自由使用锦标赛.c 中的结构体成员。但它们对 chess.c 不可见。因为它是一个不同的翻译单元。它只能看到头中的前向声明,因此它仍然是 chess.c 的不完整类型。
如果你把 typedef 写成 typedef struct tournament_t Tournament;
而没有指针声明,那么 chess.c 甚至不能声明这种类型的对象,因为它不知道结构是如何构建的。然而,它可以声明指向不完整类型对象的指针 - 您可以拥有一个指针,而无需知道它指向什么的细节。
这很可能是设计使然,这种方法被称为“不透明类型”,是您在 C 中设计私有封装的方式,以防止程序的其余部分访问结构的成员。
有些人说 typedef 一个结构体是一件坏事,但我必须这样做,因为老师们想要它。
使用或不使用 typedef 与结构体是 100% 主观的编码风格,没有对错之分。然而,将指针与 typedef 一起使用通常是有问题的,因为它可以欺骗程序员认为他们有一个普通的对象而不是一个指针。在您的情况下,它会诱使您相信您可以访问该结构。
因为它是一个不完整的类型,所以你不能在锦标赛.c 之外声明它的对象。您也不能在这样的对象上使用 sizeof
。这就是编译器错误的原因。
您应该通过让锦标赛.h 提供一个复制对象的函数来解决这个问题,而该函数又应该在锦标赛.c 中实现。请注意“不透明类型”如何迫使您进行适当的程序设计,而不是在其他不相关的文件中使用不相关的代码做不该做的事情。
,struct 的定义在 chess.c 中。类型的定义必须在要使用时可用,即在分配时可用。将定义移动到两个 c 文件共享的头文件中。