sizeof 错误:不允许不完整的类型

问题描述

我有几个 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 文件共享的头文件中。