【问题标题】:How to prevent multiple definitions in C?如何防止C中的多个定义?
【发布时间】:2010-10-14 22:29:11
【问题描述】:

我是 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|`_test'的多重定义| obj\Debug\main.o:*path*\test.c|1|首先定义在这里|

我无法对测试进行多重定义(尽管我不知道下划线的来源),而且该定义似乎不太可能以某种方式包含两次。这就是所有的代码。

我已排除此错误是由于与其他名为 test 或 test.c 的函数或文件的命名冲突造成的。请注意,多个和第一个定义在同一个文件的同一行。

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

【问题讨论】:

    标签: c multiple-definition-error


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      包含实现文件 (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 */
      

      【讨论】:

        【解决方案3】:

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

        • 删除#include "test.c"
        • 创建一个包含声明的文件 test.h: 无效测试();
        • 在 main.c 中包含文件 test.h

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            【解决方案5】:

            你实际上将test.c的源代码编译了两次:

            • 第一次编译test.c自己的时候,
            • 第二次编译 main.c 时包含所有 test.c 源代码。

            为了使用test() 函数,您在main.c 中需要的是一个简单的声明,而不是它的定义。这是通过包含一个 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
            

            【讨论】:

            • 诸如 TEST.H 这样以下划线和大写字母开头的名称在 C 用户代码中是非法的 - 它们是为编译器实现者保留的。
            • 您应该在头文件中向 test() 提供有关参数的信息,即 void test(); -> 无效测试(无效);
            • 我只是拿了问题中建议的界面,但你是对的:我更新了我的答案。
            • You actually compile the source code of test.c twice: •The first time when compiling test.c itself, •The second time when compiling main.c which includes all the test.c source. 这被接受为答案? (技术上是正确的,但它几乎没有答案)你遵守每个单元一次。编译器在当前文件中解析它可以解析的内容,然后为链接器留下钩子。链接器将解决您对test(); 的调用-并且在确定您实际指的是哪个test() 时会遇到问题
            • @LeonixSolutions:我的回答比您引用的要复杂一些。看起来它解决了OP的问题。
            【解决方案6】:

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

            祝你好运

            【讨论】:

              【解决方案7】:

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

              如下解决:

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

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

              如果你在header中初始化全局变量会出现如下错误

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

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

              希望对你有帮助

              干杯

              【讨论】:

              • 太棒了!谢谢!我把头撞到了墙上,你没有在头文件中初始化全局变量的答案解决了我的问题!非常感谢!
              【解决方案8】:

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

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

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-10-13
                • 2019-10-31
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-11-17
                相关资源
                最近更新 更多