【问题标题】:Structures, includes, forward declarations ... C结构、包含、前向声明... C
【发布时间】:2017-01-31 15:00:39
【问题描述】:

我又一次因为引用自己的结构而陷入困境...... 我知道关于这个问题有成千上万的问题,我什至自己已经发布了一个! 我就是想不通!希望这次能明白……

我有 3 个结构

    //file.h
    #ifndef _FILE
    #define _FILE

    #include "virtuald.h"

    typedef struct directory directory;

    struct file {
        directory* d;
    };
    file* createFile(virtuald*, directory*);

    #endif

    //directory.h
    #ifndef _DIR
    #define _DIR

    #include "file.h"

    struct directory {
        struct directory* father;
        file** listf;
        struct directory** listd;
    };
    directory* createDir(int, char*, int, directory*);

    #endif

    //virtualD.h
    #ifndef _VIR
    #define _VIR

    #include "directory.h"
    typedef struct file file;
    typedef virtuald {
        file** listf;
        directory** listd;
    }virtuald;
    int writeDir(int, directory*);

    #endif

如何管理包含和前向声明?我已经测试了很多东西,但我现在完全迷失了。我认为这会起作用!

我遇到了很多错误,例如: - 在 directory.h 中:未知类型名称“文件”和“目录” - 在 vi​​rtuald.h 中:未知类型名称“目录”

顺便说一句,我正在使用 -Wall -Werror -ansi -pedantic 进行编译

谢谢

【问题讨论】:

  • 它以什么方式“不工作”?
  • 不包括警卫?
  • 您似乎在 3 个标头之间存在循环依赖关系 - 这真的有必要吗?
  • 没有包含保护的循环包含是一个很有趣的秘诀。
  • 这个问题与前向声明无关,而是程序设计很差。根据您的设计:“每个文件都有一个目录,每个目录都有文件”。如果你停下来思考一下,这是无稽之谈。在现实世界中,目录有文件——文件没有目录。这就是为什么在编写一行 C 代码之前,您应该坐下来用笔和纸弄清楚所有这些依赖关系。

标签: c struct typedef


【解决方案1】:

规则 #1:保持一致!

您似乎在 typedef struct A A;struct A 之间交替声明(然后不使用 structA 后记)。

我建议你在上一个问题中删除 typedefs! 他们似乎只会让你感到困惑。

让我们举一个非常简单的例子。

这样做:

结构声明(和定义):简单,没有 typedef:

struct A {
   int x; // whatever
   int y; // whatever
   // ... etc
};

结构类型的用法:关键字struct后跟结构名称:

struct A a;
a.x = 24;
a.y = 42;

(转发)声明:

struct A;

就是这样。所有你必须知道的。 忘记typedefs总是在结构名称前使用关键字struct


你如何应用这个你的例子?让我们带上你的第一个file

使用类型 directoryvirtuald 仅作为指针,所以您只需要对它们进行前向声明:

struct directory;
struct virtuald;

定义你的结构,声明你的函数。命名结构类型时始终使用关键字struct

struct file {
    struct directory* d;
//  ^~~~~~
//  struct keyword
};

struct file* createFile(struct virtuald*, struct directory*);
//^~~~                  ^~~~~             ^~~~~~
// struct keyword for each naming of a struct type

把它们放在一起:

// file file.h
struct directory;
struct virtuald;

struct file {
    directory* d;
};
struct file* createFile(struct virtuald*, struct directory*);

【讨论】:

  • 我做错了吗?
  • 我一半同意你的观点,我认为标头应该在定义它们之前自己声明结构。例如,pastebin.com/7bxij6e2。但无论 OP 有什么明显的设计问题。
  • @Stargateur 我从未见过这种在头文件中包含之前声明结构的风格。但是我在C没有那么多经验。
  • @Stargateur 乍一看,它看起来是一个简单的解决方案。但是当我想到它时,我认为这是一个有问题的方法。这样,标头的使用取决于包含站点上存在的声明。 IE。标头不是“独立的”。当您在没有#include <string> 的标头中使用std::string 时,就像在C++ 中一样。标头应该是可包含的。
  • 这就是为什么我更喜欢我的解决方案的原因,标题在任何地方都可以包含,没有问题。声明在标题中。您的解决方案在其标头之外声明 directoryvirtuald。但两者都有效,只是风格问题。
【解决方案2】:

如果你只使用指针,告诉编译器有这样的结构就足够了。例如:

//file.h
struct directory;
struct virtuald;
struct file {
    struct directory* d;
};
struct file* createFile(struct virtuald*, struct directory*);

//directory.h
struct file;
struct directory {
    struct directory* father;
    struct file** listf;
    struct directory** listd;
};

//virtualD.h
struct file;
struct directory;
struct virtuald {
    struct file** listf;
    struct directory** listd;
};
int writeDir(int, struct directory*);

【讨论】:

    【解决方案3】:

    我会推荐以下做法。

    有 2 个包含文件,一个“公共”和一个“私有”。

    公共的(whatever.h)定义了公共 API, 私有的(可能是whateverP.h)定义whatever.c 实施需求。

    所以,例如:

    ---------whatever.h ------

    #ifndef INCLUDED_WHATEVER_H
    #define INCLUDED_WHATEVER_H
    
    typedef struct VirtualDir VirtualDir;
    typedef struct Directory  Directory;
    typedef struct File       File;
    extern File * createFile ( VirtualDir * v, Directory * d );
    
    #endif
    

    ------whateverP.h ------

    #ifndef INCLUDED_WHATEVER_P_H
    #define INCLUDED_WHATEVER_P_H
    #include "whatever.h"
    
    struct VirtualDir {
         /* whatever fields it has */
    };
    
    struct Directory {
         /* whatever fields it has */
    };
    
    struct File {
         /* whatever fields it has */
    };
    
    #endif
    

    -----whatever.c -----

    #include "whateverP.h"
    
    extern File * createFile (
            VirtualDir * v,
            Directory *  d
    ) {
         /* whatever code goes here */
    }
    

    --whateverthatwantstousewhatever.c -----

    #include "whatever.h"
    
    File * f = createFile ( blah, bleah );
    

    如果 File、VirtualDir 和 Directory 在不同的源文件中实现,规则仍然成立:blah.h 保存公共 API,blahP.h 保存私有实现细节。

    【讨论】:

      猜你喜欢
      • 2011-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 1970-01-01
      • 2012-06-09
      • 1970-01-01
      相关资源
      最近更新 更多