【问题标题】:C. Error: Duplicated function definition. What could be cause of this?C. 错误:重复的函数定义。这可能是什么原因?
【发布时间】:2021-06-09 20:00:38
【问题描述】:

我是一名初级程序员,我正在用 C 语言编写游戏“Snake”的简单实现,并使用 SDL2 库。 一切都很顺利,直到我决定将代码分成单独的文件和函数。现在,当我尝试编译我的项目时,出现了一个错误:

Snake/src\snake.c:8: duplicated definition «init_snake»; CMakeFiles\Snake.dir/objects.a(main.c.obj):Snake/src\..\src\snake.c:8: first definition

我很困惑,函数的第一个定义和它的重新定义在单个文件的同一行。我用IDE搜索了整个项目,发现只有两个地方出现了函数“init_snake”。事实上,这就是她的定义和通话的位置。在我的谷歌搜索之后,我发现我在头文件中的变量初始化方面做错了。像这样:

const static int SIZE = 10;

出于兴趣,我从头文件中删除了变量并决定不使用它们进行测试(尽管我觉得这无济于事,因为错误中是一个函数,而不是一个变量)。 它真的没有帮助。

可以肯定的是,我决定搜索有关包含的信息。为了避免代码交叉,我添加了#include guard(在互联网上找到)和#pragma once。虽然它没有帮助解决这个错误,但它很酷(如果我正确理解它是如何工作的)。

所以我来这里请教专家。这是怎么回事?因为我在一个地方定义了一个函数,然后我从另一个地方调用了一次。

下面我应用当前版本的代码。

main.c

#include "../include/main.h"

#include "../src/snake.c"

int
main(int argc,
     char *args[])
{
    SDL_Window *window = NULL;
    window = SDL_CreateWindow("Snake",
                              SDL_WINDOWPOS_CENTERED,
                              SDL_WINDOWPOS_CENTERED,
                              525,
                              525,
                              SDL_WINDOW_SHOWN);
    if (NULL == window)
    {
        printf("Window was not created. Error: %s\n", SDL_GetError());
        exit(1);
    }

    SDL_Renderer *renderer = NULL;
    renderer = SDL_CreateRenderer(window,
                                  -1,
                                  SDL_RENDERER_ACCELERATED);
    if (NULL == renderer)
    {
        printf("Renderer was not created. Error: %s\n", SDL_GetError());
        exit(1);
    }

    SDL_SetRenderDrawColor(renderer, 0x0, 0x0, 0x0, 0xFF);
    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);

    init_snake(renderer, 525 / 2, 525 / 2, 16);

    bool quit = false;
    SDL_Event e;
    while (!quit)
    {
        //Handle events on queue
        while (SDL_PollEvent(&e) != 0)
        {
            if (e.type == SDL_QUIT)
            {
                quit = true;
            }
        }
    }

    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();

    return 0;
}

main.h

#pragma once
#ifndef MAIN_H
#define MAIN_H

#include "SDL2/SDL.h"

#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

#endif

snake.c

#include "../include/snake.h"

void
init_snake(SDL_Renderer *renderer,
           int x,
           int y,
           int length)
{
    assert(renderer);

    for (int i = 0; i < length; i++)
    {
        SDL_Rect rect;
        rect.x = x;
        rect.y = y;
        rect.w = 12;
        rect.h = 10;
        SDL_SetRenderDrawColor(renderer, 0x0, 0xFF, 0x0, 0xFF);
        SDL_RenderFillRect(renderer, &rect);
        SDL_RenderPresent(renderer);
    }
}

snake.h

#pragma once
#ifndef SNAKE_H
#define SNAKE_H
    
#include "SDL2/SDL.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
    
#endif

如果我在创建这个问题时做错了什么,请告诉我 - 我会尝试解决它。如果您需要任何其他信息,请告诉我,我会澄清。 感谢您的宝贵时间。

【问题讨论】:

  • #include "../src/snake.c" from main.c 看起来像一个错误。
  • 你好,jxh!老实说,我不知道我不能包含 .c 文件。这是唯一的问题吗?我只需要只包含 .h 文件吗?
  • 只包含头文件。处理多个源文件的方式是在构建的链接阶段将它们链接在一起。
  • 谢谢各位!该程序有效!它创建了一个窗口,甚至绘制了一个绿色矩形!我很高兴!非常感谢,这对我来说是一个很好的教训:)

标签: c


【解决方案1】:

C 标准或编译器通常没有规定不能包含.c 文件。但是对于我们如何命名和使用文件有一个约定:

名称以.c 结尾的文件包含对象和/或函数的定义。对于对象,定义是编写的声明,因此它们会导致存储被保留(例如带有初始化的外部定义,例如int MyFoo = 0;,尽管这些天我们通常避免外部可见的对象)。对于函数,定义是包含函数体(它执行的代码)的声明。

名称以.h 结尾的文件包含声明 对象和/或非定义函数。这些声明仅仅描述了对象或函数而不定义它。对于对象,extern int MyFoo; 是一个描述但不定义 MyFoo 的声明。对于函数extern int bar(double x); 是一个没有定义bar 的声明。 extern 是函数的默认值,因此您可以将其关闭并编写 int bar(double x);

给定一个文件名例如MyModuleX,我们通常使用文件MyModuleX.c来定义MyModuleX的对象和功能,我们使用文件MyModuleX.h来告诉程序的其他部分这些对象以及MyModuleX 提供的功能。

所以每个使用来自MyModuleX 的东西的源文件都应该有#include "MyModuleX.h"。另外,MyModuleX.c 也应该有,所以编译器会同时看到声明和定义,并可以检查它们是否匹配。任何文件都不应该有#include "MyModuleX.c",因为我们不会通过包含源文件将函数放入程序中。相反,我们分别编译每个源文件(可能在一个命令中,但编译器会单独编译它们)并将它们链接在一起。

【讨论】:

  • 感谢您的详细解释!事情已经很清楚了。
【解决方案2】:

如果包含snake.c,则意味着它的代码在编译时会被包含两次。在文件上使用#include 只是将所有代码插入文件中。这意味着,当编译发生时,main.c 包含所有snake.c,并且由于您也在编译snake.c,因此您在其中定义的所有内容都将被定义两次。因此,您必须不将snake.c 包含在main.c 中。只需包含它的头文件。并且在头文件中,预先定义任何你想在别处使用的函数,这样你就不必为了访问这些函数而包含整个 C 文件。

【讨论】:

  • 程序有效!它创建了一个窗口,甚至绘制了一个绿色矩形!我很高兴!非常感谢!
猜你喜欢
  • 1970-01-01
  • 2020-10-16
  • 2013-06-25
  • 2016-05-10
  • 2011-11-18
  • 2014-10-08
  • 2022-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多