【问题标题】:typedef struct, circular dependency, forward definitionstypedef 结构,循环依赖,前向定义
【发布时间】:2013-06-13 01:16:56
【问题描述】:

我遇到的问题是 C 头文件中的循环依赖问题...环顾四周,我怀疑该解决方案与前向定义有关,但尽管列出了许多类似的问题,但似乎没有一个提供信息我需要解决这个问题...

我有以下 5 个源文件:

// fwd1.h
#ifndef __FWD1_H
#define __FWD1_H

#include "fwd2.h"

typedef
  struct Fwd1 {
    Fwd2  *f;
 }
Fwd1;

void  fwd1 (Fwd1 *f1,  Fwd2 *f2) ;

#endif // __FWD1_H

.

// fwd1.c
#include "fwd1.h"
#include "fwd2.h"
void  fwd1 (Fwd1 *f1,  Fwd2 *f2)  { return; }

.

// fwd2.h
#ifndef __FWD2_H
#define __FWD2_H

#include "fwd1.h"

typedef
  struct Fwd2 {
    Fwd1  *f;
  }
Fwd2;

void  fwd2 (Fwd1 *f1,  Fwd2 *f2) ;

#endif // __FWD2_H

.

// fwd2.c
#include "fwd1.h"
#include "fwd2.h"
void  fwd2 (Fwd1 *f1,  Fwd2 *f2)  { return; }

.

// fwdMain.c
#include "fwd1.h"
#include "fwd2.h"
int  main (int argc, char** argv, char** env)
{
  Fwd1  *f1 = (Fwd1*)0;
  Fwd2  *f2 = (Fwd2*)0;

  fwd1(f1, f2);
  fwd2(f1, f2);

  return 0;
}

我正在用命令编译:gcc fwdMain.c fwd1.c fwd2.c -o fwd -Wall

我尝试了几种方法来解决编译错误,但只能设法将错误替换为其他错误...如何以最少的代码更改来解决循环依赖问题? ...理想情况下,就编码风格而言,我想避免在我的代码中使用“结构”一词。

【问题讨论】:

  • 循环依赖通常是个坏主意。你能把 Fwd1 和 Fwd2 合并成一个结构吗?比如'struct Fw {Fw *f1; Fw **f2;}' ?另一件事你没有在你的'main()'中初始化'f1'和'f2'。
  • @BlueChip 如果答案解决了您的不便,请将其标记为正确,以便其他有类似不便的人知道这是一个解决方案。
  • @Thanushan Balakrishnan :您可以想象,实际 问题比这个简化的示例要复杂得多。遗憾的是,将这些元素组合起来不是一个(合理的)选项...@cgledezma - 我似乎错误地设置了我的电子邮件选项,因为我没有被告知已发布解决方案

标签: c struct typedef forward-declaration circular-dependency


【解决方案1】:

这里的问题是,当您执行循环类型时,在第一次编译器运行时,gcc 将没有完整的类型定义(这就是您收到未定义结构和东西的错误的原因),所以在适当的地方它有必要在专有名称之前放置“结构”一词。所以你的声明应该是这样的:

fwd1.h:

//fwd1.h
#ifndef __FWD1_H
#define __FWD1_H

#include "fwd2.h"

typedef struct Fwd1{
    struct Fwd2  *f;
}Fwd1;


void  fwd1 (Fwd1 *f1,  struct Fwd2 *f2) ;

#endif // __FWD1_H

fwd2.h:

// fwd2.h
#ifndef __FWD2_H
#define __FWD2_H

#include "fwd1.h"

typedef struct Fwd2{
  struct Fwd1  *f;
}Fwd2;

void  fwd2 (struct Fwd1 *f1,  Fwd2 *f2) ;

#endif // __FWD2_H

对 .c 上的函数定义执行等效更改。它应该像魅力一样发挥作用。

P.S:.h 文件的目的是声明 .c 需要的所有头文件,即:函数定义、包含等。因此,除了相应的 .h 之一之外,无需在 .c 上重复任何包含。

这意味着你的 fwd1.c 应该只包含 fwd1.h,然后所有其他包含应该放在 fwd1.h 上。

【讨论】:

  • 另一种解决方案是在 fwd1.h 中加入另一个“typedef struct Fwd2 Fwd2”,在 fwd2.h 中加入“typedef struct Fwd1 Fwd1”。
  • 或者..您可以将结构声明放在每个标头中的#include之上。
【解决方案2】:

我没有设法对此进行测试,但我认为以下变体可能会起作用。

// fwd1.h
#ifndef __FWD1_H
#define __FWD1_H

struct Fwd2; // use forward declaration of Fwd2 structure

typedef
  struct Fwd1 {
    Fwd2  *f;
 }
Fwd1;

void  fwd1 (Fwd1 *f1,  Fwd2 *f2) ;

#endif // __FWD1_H

// fwd1.c is without changes

// fwd2.h
#ifndef __FWD2_H
#define __FWD2_H

struct Fwd1; // the same trick

typedef
  struct Fwd2 {
    Fwd1  *f;
  }
Fwd2;

void  fwd2 (Fwd1 *f1,  Fwd2 *f2) ;

#endif // __FWD2_H

// fwd2.c is without changes

// fwdMain.c is without changes

【讨论】:

  • 这可以在 C++ 中使用,但在 C 中,struct 标记不是类型(除非您将 typedef 与它同名)。
【解决方案3】:

只需在 fwd1.h 顶部附近添加:

typedef struct Fwd2 Fwd2;

现在您可以将Fwd2 用作不完整类型,例如声明Fwd2* 指针。同样,在 fwd2.h 你会想要:

typedef struct Fwd1 Fwd1;

fwd1.h 和 fwd2.h 甚至不需要互相#include

【讨论】:

  • @aschelper :我被这样一个优雅的解决方案所吸引,但遗憾的是,main.c 在使用此方法时无法编译,因为 需要 包含两个标题(对于函数原型)和typedefs 的重新定义使编译器打嗝
【解决方案4】:

为了提供循环依赖的 typedef 结构的完整工作示例:

$ cat a.h
#ifndef __A_H__
#define __A_H__
typedef struct b_t b_t;
typedef struct a_t {
  b_t * b;
} a_t;
#endif //__A_H__

$ cat b.h
#ifndef __B_H__
#define __B_H__
typedef struct a_t a_t;
typedef struct b_t {
  struct a_t * a;
} b_t;
#endif //__B_H__

$ cat main.c
#include "a.h"
#include "b.h"
#include <stdio.h>
int main(int argc, char * argv[]) {
  a_t a;
  b_t b;
  a.b = NULL;
  b.a = NULL;
  printf("Done.\n");
  return 0;
}

$ cat Makefile
all: main.c a.h b.h
        gcc main.c -o main

clean:
        rm main

$ make
gcc main.c -o main

$ ./a.out
Done.

$

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多