多个定义和仅标头库
我有一个带有几个 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 文件都被编译并获得自己的代码版本,然后在链接时会导致问题,但老实说我不知道如何解决这个问题。
I have a C program with several c and h files. I decided to make one part of the program 'header-only' so I moved the code from c to h. Now I'm getting multiples definition problems and I have no idea why. e.g.:
main.c includes utils.h
vector.c includes utils.h
I moved everything in utils.c to utils.h (and of course removed utils.c from the project). utils.h starts with
#ifndef UTILS_H_
#define UTILS_H_
// and end with:
#endif
To be sure my guard was unique I tried changing it (e.g.: UTILS718171_H_) but it doesn't work.
Still, the compiler complains:
/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
...
The problem might be something like: all c files are compiled and get their own version of the code and then at linkage it causes problem, but I have honestly no idea how to solve this problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您在头文件中定义变量并将标头包含在多个 c 文件中,那么您一定会收到多个定义错误,因为您违反了一个定义规则(ODR),该规则规定应该有一个翻译单元(头文件+源文件)中只有一个定义。
解决方案是:
您应该仅定义一次出现多个定义错误的实体。
对于函数:
在头文件(包含在其他源文件中)中声明函数原型,并在一个且仅一个源文件中定义函数。
对于全局变量:
您在头文件(包含在其他源文件中)中声明变量 extern,然后在一个且仅一个源文件中定义该变量。
If you define your variables inside your header file and include the header in several c files, you are bound to get multiple definitions error because you break the One definition rule(ODR), which states that there should be only one definition in one Translation Unit(header files + source file).
Solution is:
You should define the entities you get Multiple definition errors for only once.
For Functions:
Declare the function prototypes in header file(which you include in other source files) and define the function in one and only one source file.
For Global variables:
You declare the variable extern in header file(which you include in other source files) and then define the variable in one and only one source file.
您错过了 #ifndef _FOO_H / #define _FOO_H / #endif 构造的要点。这只能防止一个文件中出现多个包含内容。例如,它们可以防止以下情况:
foo.h:
foo.c:
bar.h:
注意 foo.c 和 bar.h 都包含 foo.h;这里 #ifdef _FOO_H / #define _FOO_H / #endif 防止 foo.c 中的双重包含( bar.h 中包含的 foo.h 不会重新定义内容)
现在是下一部分。
为什么要将函数实现从 utils.c 移至 utils.h?另外,您为什么决定将其设为“仅标题”?
您可以根据您的编译器是否支持静态内联函数来执行此操作;但即便如此,也不建议这样做,因为它很可能会使您的程序不必要地臃肿,因为您的 util 函数很可能非常复杂并且无论如何都无法内联。
因此,将其改回您之前拥有的 utils.c 和 utils.h 构造,我认为它们正在工作并享受该软件。
You are missing the point of #ifndef _FOO_H / #define _FOO_H / #endif construct. That only protects against multiple inclusions in ONE file. For example they protect against this:
foo.h:
foo.c:
bar.h:
note that foo.c and bar.h both include foo.h; here the #ifdef _FOO_H / #define _FOO_H / #endif protects against that double inclusion in foo.c ( the foo.h included in bar.h doesn't redefine stuff )
Now the next part.
Why would you move function implementation from utils.c to utils.h? Also why did you decide to make it "header-only" ?
You can, depending on whether your compiler supports
static inline
functions do this; but even then it's NOT recommended, as more than likely, it will make your program unnecessarily bloated because chances are your util functions are quite complex and cannot be inlined anyways.So change it back to utils.c and utils.h construct that you had before which, i presume, WAS working and enjoy the software.
如果您希望将
utils.h
函数“复制”到使用它的每个位置,只需在标头中使用static
函数即可。 (C99 中的静态内联
)If you indend for the
utils.h
functions to be "copied" into each place where it is used, just usestatic
functions in the header. (static inline
in C99)您违反了单一定义规则。每个函数都必须精确定义一次,而您最终在每个翻译单元中定义它。
您根本不能做这样的事情:
唯一真正的解决方案是在标头中声明
void foo();
并定义< /em> 仅一次(通常在专用的 foo.c 中)。全局变量也是如此,应在标头中将其声明为 extern 并在源文件中定义。包括警卫与此无关。它们仅用于防止一个翻译单元内的递归自包含或冗余多重包含。。
You're violating the One-Definition-Rule. Each function must be defined precisely once, while you end up defining it in each translation unit.
You simply cannot do something like this:
The only real solution is to declare
void foo();
in the header and define it once only (usually in a dedicatedfoo.c
). The same goes for global variables, which should be declared asextern
in the header and defined in the source file.Include guards have nothing to do with this. They only serve to prevent recursive self-inclusion or redundant multiple inclusion within one translation unit.
我最近看到一个库,它通过在其标头底部有第二个 ifdef 块来实现此目的,其中包含实现等,并要求在您的一个 c 文件中添加例如
#define FOO_IMPL
。这意味着可以在需要的地方添加声明,但实现只会编译一次。所以:library.h
(加上任何其他样板文件)
program.c
(我没有尝试编译我的示例代码,但希望它能说明问题。)
I recently saw a library that accomplished this by having a second ifdef block at the bottom of their header, containing the implementations etc., with the injunction that in ONE of your c files, you add e.g.
#define FOO_IMPL
. This meant that the declarations would be added wherever they were needed, but the implementations would only be compiled once. So:library.h
(plus whatever other boilerplate)
program.c
(I didn't try to compile my example code, but hopefully it gets the point across.)