54

我是 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;
}

测试.c:

void test() {}

当我尝试构建这个程序时,它给出了以下错误:

*path*\test.c|1|`_test'的多重定义|
obj\Debug\main.o:*path*\test.c|1|首先定义在这里|

我不可能多次定义测试(尽管我不知道下划线来自哪里),而且定义似乎不太可能以某种方式被包含两次。这就是所有的代码。

我已经排除了这个错误是由于与其他函数或文件被称为 test 或 test.c 的一些命名冲突。请注意,多个定义和第一个定义位于同一文件的同一行。

有谁知道是什么原因造成的,我能做些什么?谢谢!

4

8 回答 8

106

你实际上编译了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
于 2009-03-23T10:00:19.743 回答
27

下划线由编译器放在那里并由链接器使用。基本路径是:

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()。

于 2009-03-23T09:55:19.087 回答
11

您不应在.c 文件中包含其他源文件 (*.c)。我想你想要一个带有测试函数声明的头文件(.h),并将它的定义放在一个单独的.c 文件中。

该错误是由测试函数的多个定义引起的(一个在test.c中,另一个在main.c中)

于 2009-03-23T09:48:52.127 回答
6

我有类似的问题,我按照以下方式解决了。

解决如下:

函数原型声明和全局变量应该在 test.h 文件中,并且不能在头文件中初始化全局变量。

test.c文件中全局变量的函数定义和使用

如果您在标头中初始化全局变量,则会出现以下错误

`_ test'的多重定义| obj\Debug\main.o:路径\test.c|1|首次定义在这里|

只是在头文件中声明全局变量,没有初始化应该起作用。

希望能帮助到你

干杯

于 2012-09-25T10:20:40.523 回答
4

包含实现文件 ( test.c) 会导致它被添加到您的 main.c 并在那里编译,然后再次单独编译。因此,该函数test有两个定义——一个在 的目标代码中,一个在 的目标代码中main.ctest.c这会给您带来 ODR 违规。您需要创建一个包含声明的头文件test并将其包含在main.c

/* test.h */
#ifndef TEST_H
#define TEST_H
void test(); /* declaration */
#endif /* TEST_H */
于 2009-03-23T09:51:33.213 回答
4

如果您已将 test.c 添加到您的 Code::Blocks 项目中,则该定义将被看到两次——一次通过#include,一次通过链接器。你需要:

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

于 2009-03-23T09:52:48.670 回答
4

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

祝你好运

于 2009-03-23T10:16:14.853 回答
1

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

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

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

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

于 2021-07-06T20:08:26.047 回答