我是C新手,我只是想用Code :: Blocks编写一个控制台应用程序。这是(简化)代码: main.c中:
#include <stdio.h>
#include <stdlib.h>
#include "test.c" // include not necessary for error in Code::Blocks
int main()
{
//t = test(); // calling of method also not necessary
return 0;
}
test.c的:
void test() {}
当我尝试构建此程序时,它会出现以下错误:
*path*\test.c|1|multiple definition of `_ test'| obj\Debug\main.o:*path*\test.c|1|first defined here|
我无法多次定义测试(尽管我不知道下划线的来源),并且似乎不太可能将定义以某种方式包含两次。这就是所有代码。
我已经排除了这个错误是由于某些命名与其他函数或文件名称test或test.c冲突造成的。请注意,多个和第一个定义位于同一文件的同一行。
有谁知道造成这种情况的原因以及我能做些什么呢?谢谢!
答案 0 :(得分:81)
您实际上编译了test.c
两次的源代码:
test.c
本身时,main.c
来源的test.c
。为了使用main.c
函数,您在test()
中需要的是一个简单的声明,而不是它的定义。这是通过包含test.h
头文件来实现的,该文件包含以下内容:
void test(void);
这通知编译器存在具有输入参数和返回类型的这种函数。此功能的作用({
和}
内的所有内容)都保留在test.c
文件中。
在main.c中,将#include "test.c"
替换为#include "test.h"
。
最后一点:如果您的程序更复杂,您将面临多次包含头文件的情况。为防止这种情况,标题源有时会被特定的宏定义所包围,例如:
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
void test(void);
#endif
答案 1 :(得分:25)
下划线由编译器放在那里并由链接器使用。基本路径是:
main.c
test.h ---> [compiler] ---> main.o --+
|
test.c ---> [compiler] ---> test.o --+--> [linker] ---> main.exe
因此,您的主程序应包含测试模块的头文件,该头文件应仅包含声明,例如函数原型:
void test(void);
这使得编译器知道它在编译main.c时存在,但实际代码在test.c中,然后是test.o。
这是将两个模块连接在一起的链接阶段。
通过将test.c包含到main.c中,您将在main.o中定义test()函数。据推测,您将链接main.o和test.o,两者都包含函数test()。
答案 2 :(得分:10)
您不应在 .c文件中包含其他源文件(* .c)。我想你想要一个包含测试函数DECLARATION的头文件( .h)文件,并在一个单独的.c文件中使用它的DEFINITION。
错误是由测试函数的多个定义引起的(一个在test.c中,另一个在main.c中)
答案 3 :(得分:6)
我有类似的问题,我按照方式解决了。
解决如下:
函数原型声明和全局变量应该在test.h文件中,你不能在头文件中初始化全局变量。
test.c文件中函数定义和全局变量的使用
如果在头文件中初始化全局变量,则会出现以下错误
`_ test'|的多重定义 obj \ Debug \ main.o: path \ test.c | 1 |首先在此定义|
只是在Header文件中声明全局变量,没有初始化应该有效。
希望有所帮助
干杯
答案 4 :(得分:4)
包含实现文件(test.c
)会使它被添加到main.c中并在那里进行编译,然后再单独进行。因此,函数test
有两个定义 - 一个在main.c
的目标代码中,一个在test.c
的定义中,这会给您一个ODR违规。您需要创建一个包含test
声明的头文件,并将其包含在main.c
中:
/* test.h */
#ifndef TEST_H
#define TEST_H
void test(); /* declaration */
#endif /* TEST_H */
答案 5 :(得分:4)
如果已将test.c添加到Code :: Blocks项目中,则定义将被看到两次 - 一次通过#include,一次通过链接器。你需要:
答案 6 :(得分:4)
如果您正在使用Visual Studio,您还可以在头文件的顶部执行“#pragma once”以实现与“#ifndef ...”相同的功能 - 包装。其他一些编译器也可能支持它。 ..但是,不要这样做:D坚持#ifndef-wrapping以实现交叉编译器兼容性。我只是想让你知道你也可以做一次#pragma,因为你在阅读其他人的代码时可能会遇到这个陈述。
祝你好运
答案 7 :(得分:0)
此后多年,我发现了另一个导致相同错误的问题,但在任何地方都找不到答案。我想把它放在这里供其他遇到同样问题的人参考。
我在头文件中定义了一个函数,它一直抛出这个错误。 (我知道这不是正确的方法,但我想我会很快用这种方式测试它。)
解决方案是仅在头文件中放置声明,在 cpp 文件中放置定义。
原因是头文件没有被编译,它们只提供定义。