![](/img/trans.png)
[英]what could cause multiple definition error again after I declare the function inline?
[英]C. Error: Duplicated function definition. What could be cause of this?
我是一名初學者程序員,我正在使用 C 語言並使用 SDL2 庫編寫游戲“Snake”的簡單實現。 一切都很順利,直到我決定將代碼分成單獨的文件和函數。 現在,當我嘗試編譯我的項目時出現錯誤:
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
我很困惑 function 的第一個定義及其重新定義位於單個文件的同一行。 我用 IDE 搜索了整個項目,發現只有兩個地方出現了 function “init_snake”。 事實上,這就是她的定義和電話的位置。 在我的谷歌搜索之后,我發現我在 header 文件中初始化變量時出錯的信息。 像這樣:
const static int SIZE = 10;
為了感興趣,我從 header 文件中刪除了變量,並決定不使用它們進行測試(盡管我覺得這無濟於事,因為錯誤是 function,而不是變量)。 它真的沒有幫助。
可以肯定的是,我決定搜索有關包含的信息。 為了避免代碼交叉,我添加了 #include guard(在 Internet 上找到)和#pragma once
。 雖然它對這個錯誤沒有幫助,但它很酷(如果我正確理解它是如何工作的)。
所以特地來這里請教專家。 這是怎么回事? 因為我在一個地方定義了一個 function,然后我從另一個地方調用它一次。
下面我應用當前版本的代碼。
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;
}
主文件
#pragma once
#ifndef MAIN_H
#define MAIN_H
#include "SDL2/SDL.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#endif
蛇.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);
}
}
蛇.h
#pragma once
#ifndef SNAKE_H
#define SNAKE_H
#include "SDL2/SDL.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#endif
如果我在創建這個問題時做錯了什么,請告訴我 - 我會嘗試解決它。 如果您需要任何其他信息,請告訴我,我會澄清。 感謝您的時間。
C 標准或編譯器通常沒有規定您不能包含.c
文件。 但是對於我們如何命名和使用文件有一個約定:
名稱以.c
結尾的文件包含對象和/或函數的定義。 對於對象,定義是編寫的聲明,以便它們導致存儲被保留(例如具有初始化的外部定義,例如int MyFoo = 0;
,盡管這些天我們通常避免外部可見的對象)。 對於函數,定義是包含 function(它執行的代碼)主體的聲明。
名稱以.h
結尾的文件包含不是定義的對象和/或函數的聲明。 這些聲明僅描述了 object 或 function 沒有定義它。 對於對象, extern int MyFoo;
是一個描述但不定義MyFoo
的聲明。 對於 function extern int bar(double x);
是一個沒有定義bar
的聲明。 extern
是 function 的默認值,因此您可以將其關閉並寫入int bar(double x);
.
給定一個文件名,例如MyModuleX
,我們通常使用文件MyModuleX.c
來定義MyModuleX
的對象和函數,我們使用文件MyModuleX.h
來告訴程序的其他部分MyModuleX
提供的對象和函數。
所以每個使用MyModuleX
的源文件都應該有#include "MyModuleX.h"
。 此外, MyModuleX.c
也應該有,所以編譯器會同時看到聲明和定義,並可以檢查它們是否匹配。 沒有文件應該有#include "MyModuleX.c"
,因為我們不會通過包含源文件將函數放入程序中。 相反,我們分別編譯每個源文件(可能在一個命令中,但編譯器將單獨編譯它們)並將它們鏈接在一起。
如果你包含snake.c
,這意味着它的代碼在編譯時會被包含兩次。 在文件上使用#include
只是將所有代碼插入文件中。 意思是,當編譯發生時, main.c
包含所有snake.c
,並且由於您也在編譯snake.c
將定義兩次。 因此,您必須在main.c
snake.c
只需包含其 header 文件即可。 在 header 文件中,預定義您想在其他地方使用的任何功能,因此您不必包含整個 C 文件即可訪問這些功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.