【问题标题】:Linker issue with header file头文件的链接器问题
【发布时间】:2016-02-09 20:31:53
【问题描述】:

在 C 应用程序中,我有一个 main.c 文件:

#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main(int argc, const char * argv[])
{
    foo f;
    bar b;
    return 0;
}

foo.h(和 foo.c 文件):

#ifndef foo_h
#define foo_h
#include <stdio.h>
#include "bar.h"
#include "utility.h"
typedef struct foo foo;
typedef struct bar bar;
struct foo {
    bar * b;
    int a;
};
#endif

bar.h(和 bar.c 文件):

#ifndef bar_h
#define bar_h
#include <stdio.h>
#include "foo.h"
typedef struct foo foo;
typedef struct bar bar;
struct bar {
    foo * f;
    int a;
};
int get_b_a(bar b);
#endif

还有一个utility.h(没有utility.c):

#ifndef utility_h
#define utility_h
int add(int a, int b);
int add(int a, int b)
{
    return a + b;
}
#endif

然而,这个程序不会在 xcode 中构建,因为它抱怨链接器问题: Duplicate symbol _add in bar.o and main.o

我知道我可以通过创建一个单独的 utility.c 文件轻松解决这个问题,但是我不希望这样做,因为它会导致更大的项目中的文件过多。

解决上述问题的最佳实践是什么?

【问题讨论】:

  • 这就是为什么我们使用源文件,而不是全头代码...
  • @SouravGhosh 我知道,但这并不总是很方便,例如在一个头文件中构建 API。
  • 如果你使用一种语言,你必须遵守它的约定。有些事情是有创意的——这不是其中之一。为什么以及如何使用标题在每本 C 书籍中都有解释。
  • @Olaf 在这种情况下,约定是什么?创建utility.c?我问是因为我认为可能有另一种方法?
  • 对不起,堆栈溢出不是一个教程网站。恐怕你真的要读一本书。您需要了解全貌。

标签: c xcode linker


【解决方案1】:

问题似乎是您的包含太多

你不需要

#include "bar.h"

在 foo.h 中,因为您将它包含在 main.c 中

发生的事情是前驱将在程序编译之前将所有内容组合起来......

...所以正在发生的事情是将 foo.h 和 bar.h 的一份副本加载到 main 中,然后在 foo.h 和 bar.h 中重新加载 bar.h 和 foo.h

所以删除

#include "bar.h"

来自 foo.h

并删除

#include "foo.h"

来自 bar.h

看起来你的类型定义太多了

typedef struct foo foo;

这应该只在整个代码中出现一次。

在 cmets 之后编辑....

你可以在 main.c 中有一个层次结构

#include "foo.h"

并且不要包含“bar.h”

然后在 foo.h 你可以有

#include "bar.h"

然后您的程序中将只有一份 foo.h 和 bar.h 的副本。 (在 bar.h 中你不想有任何#includes)

【讨论】:

  • 但是它不会是“可移植的”,在另一个应用程序中我可能希望只在 main 中包含“foo.h”,因为只有 foo 直接使用?
  • @sigvardsen - 那么,如果您只想包含“foo.h”,是否需要“bar.h”才能包含在“foo.h”中?如果 foo.h 和 bar.h 做分开的事情,那么你可以将它们分开,但如果你需要两者一起工作,那么最好将它们结合起来
  • 重点是不能分开,我也考虑过合并。但是,您可能会想到一个您只想直接处理 foo 的程序,因此只将其包含在主文件中,并将 bar 留给其他函数处理。
  • @sigvardsen - 好的 - 那么你应该在 main 中 #include "foo.h" 而在 foo 中而不是在 main 中 #include "bar.h" - 那么你将只有一份 foo .h 和一份 bar.h - 我将编辑答案....
  • 我知道,但关键是我必须根据实现更改 foo 和 bar 。我想我将使用 .c 文件作为实用程序。谢谢你的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
相关资源
最近更新 更多