22

我有一个包含几个 c 和 h 文件的 C 程序。我决定将程序的一部分设为“仅标题”,因此我将代码从 c 移至 h。现在我遇到了多重定义问题,我不知道为什么。例如:

main.c includes utils.h
vector.c includes utils.h

我将 utils.c 中的所有内容都移到了 utils.h(当然还从项目中删除了 utils.c)。utils.h 以

#ifndef UTILS_H_
#define UTILS_H_

// and end with:
#endif

为了确保我的后卫是独一无二的,我尝试改变它(例如:UTILS718171_H_)但它不起作用。

尽管如此,编译器仍然抱怨:

/tmp/ccOE6i1l.o: In function `compare_int':
ivector.c:(.text+0x0): multiple definition of `compare_int'
/tmp/ccwjCVGi.o:main.c:(.text+0x660): first defined here
/tmp/ccOE6i1l.o: In function `compare_int2':
ivector.c:(.text+0x20): multiple definition of `compare_int2'
/tmp/ccwjCVGi.o:main.c:(.text+0x6e0): first defined here
/tmp/ccOE6i1l.o: In function `matrix_alloc':
ivector.c:(.text+0x40): multiple definition of `matrix_alloc'
/tmp/ccwjCVGi.o:main.c:(.text+0x0): first defined here
...

问题可能是这样的:所有c文件都被编译并获得他们自己的代码版本,然后在链接时它会导致问题,但老实说我不知道​​如何解决这个问题。

4

4 回答 4

32

如果您在头文件中定义变量并将头文件包含在多个 c 文件中,则必然会出现多个定义错误,因为您违反了一个定义规则(ODR) ,该规则规定一个翻译单元中应该只有一个定义(头文件+源文件)。

解决方案是:
您应该只定义一次获得多个定义错误的实体。
对于函数:
在头文件(您包含在其他源文件中)中声明函数原型,并在一个且只有一个源文件中定义函数。
对于全局变量:
您在头文件(包含在其他源文件中)中声明变量 extern,然后在一个且只有一个源文件中定义该变量。

于 2011-11-20T13:52:59.910 回答
11

您错过了 #ifndef _FOO_H / #define _FOO_H / #endif 构造的要点。这只能防止在一个文件中包含多个内容。例如,它们可以防止这种情况:

富.h:

  #ifndef _FOO_H 
  #define _FOO_H

  /* some C stuff here */

  #endif /* _FOO_H */

富.c:

   #include <foo.h>
   #include <bar.h>
   ...

酒吧.h:

   #include <foo.h>
   ...

注意 foo.c 和 bar.h 都包含 foo.h;这里 #ifdef _FOO_H / #define _FOO_H / #endif 防止 foo.c 中的双重包含(bar.h 中包含的 foo.h 不会重新定义东西)

现在下一部分。

为什么要将函数实现从 utils.c 移到 utils.h?另外,您为什么决定将其设为“仅标题”?

您可以根据您的编译器是否支持static inline函数来执行此操作;但即便如此,也不建议这样做,因为它很可能会使您的程序不必要地臃肿,因为您的 util 函数很可能非常复杂并且无论如何都不能内联。

因此,将其改回您之前拥有的 utils.c 和 utils.h 构造,我想,WAS 正在工作并享受该软件。

于 2011-11-20T14:02:31.333 回答
5

你违反了单一定义规则。每个函数必须精确定义一次,而您最终在每个翻译单元中定义它。

你根本不能做这样的事情:

// header.h
void foo() { }

// file1.c
#include "header.h"

// file2.c
#include "header.h"

唯一真正的解决方案是在标头中声明并仅 定义一次(通常在专用的 中)。全局变量也是如此,它应该在头文件中声明并在源文件中定义。void foo();foo.cextern

包括警卫与此无关。它们仅用于防止递归自包含或一个翻译单元内的冗余多重包含。

于 2011-11-20T13:54:29.037 回答
4

如果您打算将函数“复制”到每个使用它的地方,只需在标题中utils.h使用函数。staticstatic inline在 C99 中)

于 2011-11-20T14:09:00.503 回答