如何防止C中的多个定义?

时间:2009-03-23 09:46:01

标签: c multiple-definition-error

我是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冲突造成的。请注意,多个和第一个定义位于同一文件的同一行。

有谁知道造成这种情况的原因以及我能做些什么呢?谢谢!

8 个答案:

答案 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,一次通过链接器。你需要:

  • 删除#include“test.c”
  • 创建一个包含声明的文件test.h:    void test();
  • 在main.c中包含文件test.h

答案 6 :(得分:4)

如果您正在使用Visual Studio,您还可以在头文件的顶部执行“#pragma once”以实现与“#ifndef ...”相同的功能 - 包装。其他一些编译器也可能支持它。 ..但是,不要这样做:D坚持#ifndef-wrapping以实现交叉编译器兼容性。我只是想让你知道你也可以做一次#pragma,因为你在阅读其他人的代码时可能会遇到这个陈述。

祝你好运

答案 7 :(得分:0)

此后多年,我发现了另一个导致相同错误的问题,但在任何地方都找不到答案。我想把它放在这里供其他遇到同样问题的人参考。

我在头文件中定义了一个函数,它一直抛出这个错误。 (我知道这不是正确的方法,但我想我会很快用这种方式测试它。

解决方案是在头文件中放置声明,在 cpp 文件中放置定义。

原因是头文件没有被编译,它们只提供定义。