多个定义和仅限标头的库

Suu*_*aku 15 c include multiple-definition-error

我有一个带有几个c和h文件的C程序.我决定将程序的一部分设置为"仅限标题",因此我将代码从c移到了h.现在我得到了多重定义问题,我不明白为什么.例如:

main.c includes utils.h
vector.c includes utils.h
Run Code Online (Sandbox Code Playgroud)

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

#ifndef UTILS_H_
#define UTILS_H_

// and end with:
#endif
Run Code Online (Sandbox Code Playgroud)

为了确保我的后卫是独一无二的,我尝试改变它(例如: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
...
Run Code Online (Sandbox Code Playgroud)

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

Alo*_*ave 21

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

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

  • 尽管这个答案被接受,但它不是这个问题的正确答案,因为它忽略了整个要点:OP希望使用仅头文件,所有声明和定义都在同一个文件中。即使没有 Arduino IDE,在 Arduino 环境中也有必要这样做,这是有正当理由的。这个答案只是指出您不应该使用仅头文件。有三种方法可以解决多重定义问题,每种方法都有不同的含义和成本。IMO 这里适用的解决方案是将任何非成员函数声明为内联函数。 (4认同)

Ahm*_*sud 10

你错过了#ifndef _FOO_H/#define _FOO_H/#endif构造的观点.这只能防止一个文件中的多个包含.例如,他们防止这种情况:

foo.h中:

  #ifndef _FOO_H 
  #define _FOO_H

  /* some C stuff here */

  #endif /* _FOO_H */
Run Code Online (Sandbox Code Playgroud)

foo.c的:

   #include <foo.h>
   #include <bar.h>
   ...
Run Code Online (Sandbox Code Playgroud)

bar.h:

   #include <foo.h>
   ...
Run Code Online (Sandbox Code Playgroud)

注意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正在工作并享受该软件.


u0b*_*6ae 6

如果您希望utils.h将函数“复制”到每个使用它的地方,只需使用static标头中的函数即可。(static inline在 C99 中)


Ker*_* SB 5

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

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

// header.h
void foo() { }

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

// file2.c
#include "header.h"
Run Code Online (Sandbox Code Playgroud)

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

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