为什么我不能在ListFunction.h中包含ListDefinition.h

时间:2017-11-04 11:55:06

标签: c

我将C程序拆分为多个文件。这是他们的样子。

ListDefinition.h

#ifndef ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H
#define ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H

extern typedef struct type DataType; //this is a struct declaration about basic data type in the list

extern typedef struct s_list SeqList, *PseqList; //this is a struct declaration about sequence list

extern typedef struct sl_list SlinkList, *PSlinkList; //this is a struct declaration about linked list

#endif //ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H

或删除extern

#ifndef ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H
#define ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H

typedef struct type DataType; //this is a struct declaration about basic data type in the list

typedef struct s_list SeqList, *PseqList; //this is a struct declaration about sequence list

typedef struct sl_list SlinkList, *PSlinkList; //this is a struct declaration about linked list

#endif //ALGORITHM_AND_DATASTRUCTURE_LISTDEFINITION_H

ListDefinition.c

#include "ListDefinition.h"
#define MAXSIZE 100
typedef struct type {
    int date;
}DataType;

typedef struct s_list {
    DataType a[MAXSIZE];
    int length;
    int top;
}SeqList, *PseqList;

typedef struct sl_list {
    DataType node;
    struct sl_list *next;
}SlinkList, *PSlinkList;

我想在ListDefinition.h

中使用ListFunction.h

ListFunction.h

#ifndef ALGORITHM_AND_DATASTRUCTURE_LISTFUNCTION_H
#define ALGORITHM_AND_DATASTRUCTURE_LISTFUNCTION_H

#include "ListDefinition.h"

PseqList initial_seqList(PseqList PL);//The function be used to initialize the sequence list

int search_seqlist(PseqList PL, DataType x);//the function be used to search the x in the sequence list

#endif //ALGORITHM_AND_DATASTRUCTURE_LISTFUNCTION_H

ListFunction.c

#include <stdio.h>
#include <stdlib.h>
#include "ListFunction.h"
PseqList initial_seqList(PseqList PL) {
    PL=malloc(sizeof(SeqList));
    if(PL == NULL) {
        exit(1);
        printf("The memory isn't allocated");
    }
    PL->length = 0;
    PL->top = -1;
    return PL;
}
int search_seqlist(PseqList PL, DataType x) {
    int i;
    for(i = 0;i < PL->length; i++) {
        if(PL->a[i].date == x.date)
            break;
    }
    if (i == PL->length)
        return 0;
    else
        return i+1;
}

您不关心代码的含义。出现了许多错误,但是当我在#include "ListDefinition.h"中将#include "ListDefinition.c"更改为ListFunction.h时。所有错误都消失了,我想知道为什么? This problem似乎告诉我应该使用ListFunction.h。我在Clion中运行代码。

1 个答案:

答案 0 :(得分:0)

extern typedef的组合在C中是非法的。两个关键字都是&#39;存储类&#39;,并且您只能在声明中拥有一个存储类。放下extern; typedef没有存储空间(它没有定义任何对象),因此没有其他地方定义的存储空间&#39;使extern有用。如果删除typedef,则会尝试声明不完整类型的变量。

您的代码似乎正在尝试实施&#39; opaque类型&#39;。这可能是一项很好的技巧 - 如果你小心的话。但是,要小心包括:

  • 客户端代码永远不需要取消引用结构类型的内部。
  • 客户端代码永远不需要分配类型的结构(它只会使用指向该类型的指针)。
  • 功能界面足够完整,允许客户端代码执行任何需要执行的操作。

因此,您可以定义一个类似于ListFunction.h的标题,其中包含ListDefinition.h的内容 - 结构类型的typedef(没有单独的标题) - 以及功能声明。您的客户端代码可以使用它。

您可能有一个标题(不是源文件)等同于ListDefinition.c中的标题,除了结构定义只是定义结构内容;它不包括typedef或typedef名称。这将是一个私人的&#39;头。它只能由实现提供对ListDefinition.h中声明的opaque类型的访问的函数的代码使用。如果您需要在多个源文件中使用该信息,则只能创建第二个标头。如果仅在一个源文件中需要该信息,则您将该信息保留在该源文件中(仅限)。

您的设计要求DataType不透明。您的函数接口要求调用代码传递DataType的副本,因此调用代码必须能够为DataType分配存储空间。此外,您没有提供一套管理DataType值的功能。因此,您必须在ListFunction.h标题中显示该结构。

使用opaque结构指针比在接口中使用void指针要好得多。使用void指针会使代码容易被滥用 - 任何类型的任何指针都可以传递给需要void *参数的函数。相比之下,如果某个函数需要SeqList *,则无法将FILE *char *DataType *传递给该函数(尽管您可以明确传递某些内容)定义为void *因为void *可以在C(但不是C ++)中转换为任何其他对象指针类型)。尽可能避免使用void *

请注意Is it a good idea to typedef pointers?中的讨论 - 简洁的答案是&#39;否&#39;。

您与initial_seqlist()的界面充其量是可疑的。实现表明你不应该接受任何参数(因为你的代码所做的第一件事就是覆盖作为参数传递的值)。它应该是SeqList *initial_seqlist(void)

注意到没有声明操作Slinklist类型的函数,代码可能会变成:

listdef11.h

#ifndef LISTDEF11_H_INCLUDED
#define LISTDEF11_H_INCLUDED

typedef struct DataType
{
    int date;
} DataType;

typedef struct SeqList SeqList;

extern SeqList *initial_seqList(void);
extern int search_seqlist(SeqList *PL, DataType x);

/* ... */

#endif /* LISTDEF11_H_INCLUDED */

listdef11.c

#include "listdef11.h"
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 100

struct SeqList
{
    DataType a[MAXSIZE];
    int length;
    int top;
};

SeqList *initial_seqList(void)
{
    SeqList *psl = malloc(sizeof(*psl));
    if (psl == NULL)
    {
        fprintf(stderr, "Failed to allocate %zu bytes of memory in %s()\n",
                sizeof(*psl), __func__);
        exit(1);
    }
    psl->length = 0;
    psl->top = -1;
    return psl;
}

int search_seqlist(SeqList *psl, DataType x)
{
    for (int i = 0; i < psl->length; i++)
    {
        if (psl->a[i].date == x.date)
            return i + 1;
    }
    return 0;
}

代码中还有许多其他更改。我并不同意所有的设计决策(例如,top成员似乎未使用或与length基本相同;我认为应该这样做。但这至少可以编译。 listdef11.h的消费者可以做必要的事情 - 或者,如果listdef11.h中声明的支持函数列表更完整,他们可以做到。该清单至少包括一个析构函数和一个插入器;它可能需要包括更多。用户对search_seqlist()返回的号码可能做的事情并不完全明显。