【问题标题】:Why I can't include ListDefinition.h in ListFunction.h为什么我不能在 ListFunction.h 中包含 ListDefinition.h
【发布时间】:2017-11-04 11:55:06
【问题描述】:

我将一个 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;

我想在ListFunction.h 中使用ListDefinition.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;
}

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

【问题讨论】:

  • 我想问题是ListDefinition.c 包含应该在.h 文件中的声明。我以前从未见过extern typedef struct,也不知道那是什么意思。
  • extern 关键字用于在编译后链接数据对象或函数。尽管如此,编译所需的所有信息都必须在文件中可用。因此,您不能有类似 extern 类型的声明。如果您主动隐藏定义,编译器应该如何知道SeqList的外观。
  • @Gerhardh 如果我删除 extern?
  • 永远不要以这种方式更新您的问题,让所有 cmets 无用!
  • 删除 extern 没有帮助。类型定义仍然缺失。

标签: c


【解决方案1】:

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

您的代码似乎正在尝试实现“不透明类型”。这可能是一个很好的技术——如果你小心的话。但是,要小心包括:

  • 客户端代码永远不需要取消引用结构类型的内部。
  • 客户端代码永远不需要分配该类型的结构(它只会使用指向该类型的指针)。
  • 函数接口足够完整,可以让客户端代码做它需要做的任何事情。

因此,您可以定义像 ListFunction.h 这样的标头,其中将包括 ListDefinition.h 的内容——结构类型的 typedefs(没有单独的标头)——以及函数声明。您的客户端代码可以使用它。

你可能有一个与ListDefinition.c 相同的头文件(不是源文件),除了结构定义将简单地定义结构内容;它不包括 typedef 或 typedef 名称。这将是一个“私人”标题。它只会被实现函数的代码使用,这些函数提供对ListDefinition.h 中声明的不透明类型的访问。如果您在多个源文件中需要该信息,则只需创建第二个标头。如果仅在一个源文件中需要该信息,则应将信息保留在该源文件中(仅)。

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

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

还要注意Is it a good idea to typedef pointers? 中的讨论——简洁的答案是“不”。

您与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() 返回的数字做什么并不完全清楚。

【讨论】:

  • 多么详细且易于理解的答案!非常感谢。
猜你喜欢
  • 1970-01-01
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多