本人在寫學生信息管理系統時遇到一個很頭疼的錯誤——error LNK2005重覆定義錯誤,苦思冥想百度谷歌bing之後都沒能解決問題,於一清早剎那間覺得知道問題出在哪兒了,於是乎起床、開機、修改代碼一氣呵成,終於0 error(s)\0 warning(s)。 error LNK2005錯誤分為好幾 ...
本人在寫學生信息管理系統時遇到一個很頭疼的錯誤——error LNK2005重覆定義錯誤,苦思冥想百度谷歌bing之後都沒能解決問題,於一清早剎那間覺得知道問題出在哪兒了,於是乎起床、開機、修改代碼一氣呵成,終於0 error(s)\0 warning(s)。
error LNK2005錯誤分為好幾種,我以下分析的是重覆定義外部函數,如果是因為重覆定義全局變數、頭文件的重覆包含、或者使用第三方庫原因導致的error LNK2005請移步http://www.cnblogs.com/MuyouSome/p/3332699.html
一:問題描述
我的系統分為3個文件(stuheader.h、stufun.c、stuims.c)
- stuheader.h:該文件中包含頭文件、結構體定義以及函數聲明等;
- stufun.c:該文件是系統中除main函數外的其他自定義函數的實現和相互調用;
- stuims.c:該文件是主函數main調用其他函數組裝的整個軟體系統。
#include<stdio.h> //I/O函數 #include<stdlib.h> //標準庫函數 #include<string.h> //字元串函數 #include<ctype.h> //字元操作函數 #define M 50 //定義常數表示記錄數 typedef struct { char no[20]; //學號 char name[20]; //姓名 char sex[5]; //性別 int age; //年齡 }STUDENTS; //以下是函數原型 int menu_select(); //主菜單函數 int enter(STUDENTS t[]); //輸入記錄 void list(STUDENTS t[],int n); //顯示記錄 void search(STUDENTS t[],int n); //按姓名查找顯示記錄 int del(STUDENTS t[],int n); //刪除記錄 int add(STUDENTS t[],int n); //插入記錄 void save(STUDENTS t[],int n); //記錄保存為文件 int load(STUDENTS t[]); //從文件中讀記錄 void display(STUDENTS t[],int n); //按序號查找顯示記錄 void sort(STUDENTS t[],int n); //按姓名排序 void copy(); //文件複製 void print(STUDENTS temp); //顯示單條記錄 int find_name(STUDENTS t[],int n,char *s); //按姓名查找函數 int find_no(STUDENTS t[],int n,char *no); //按學號查找 void modify(STUDENTS t[],int n); //修改記錄stuheader.h代碼
#include "stuheader.h" //菜單函數,返回值為整數,代表所選的菜單項 int menu_select() { } int enter(STUDENTS t[]) { } //顯示記錄,參數為記錄數組和記錄條數 void list(STUDENTS t[],int n) { } //查找記錄 void search(STUDENTS t[],int n) { } //刪除函數,參數為記錄數組和記錄條數 static int del(STUDENTS t[],int n) { return 0; } //插入記錄函數,參數為結構體數組和記錄數 int add(STUDENTS t[],int n) { return 0; } //保存函數,參數為結構體數組和記錄數 void save(STUDENTS t[],int n) { } //讀入函數,參數為結構體數組 int load(STUDENTS t[]) { return 0; } //按序號顯示記錄函數 void display(STUDENTS t[],int n) { } //按姓名排序函數 void sort(STUDENTS t[],int n) { } //複製文件 void copy() { } //顯示指定的一條記錄 void print(STUDENTS temp) { } //按姓名查找函數,參數為記錄數組和記錄條數以及姓名s int find_name(STUDENTS t[],int n,char *s) { return 0; } //按學號查找函數,參數為記錄數組和記錄條數以及學號no int find_no(STUDENTS t[],int n,char *no) { return 0; } //修改函數,按照輸入學號修改 void modify(STUDENTS t[],int n) { }stufun.c 代碼(其中函數體已省略)
stuims.c 文件中代碼如下:
#include "stufun.c" //stufun.c中已經包含了stufun.h void main() { STUDENTS stu[M]; //定義結構體數組 int length; //保存記錄長度 for(;;) //無限迴圈 { system("cls"); switch(menu_select()) { case 0:length=enter(stu);break; //輸入記錄 case 1:list(stu,length);break; //顯示全部記錄 case 2:search(stu,length);break; //按姓名查找記錄 case 3:length=del(stu,length);break;//按姓名刪除記錄 case 4:modify(stu,length);break; //按學號修改記錄 case 5:length=add(stu,length);break;//插入記錄 case 6:save(stu,length);break; //保存文件 case 7:length=load(stu);break; //載入文件到記憶體 case 8:display(stu,length);break; //按序號顯示記錄 case 9:sort(stu,length);break; //按姓名排序 case 10:copy();break; //複製文件到目標文件 case 11:exit(0); //程式結束 } printf("按回車鍵回主菜單...\n"); getchar(); } }
我的基本思路是用stufun.c文件包含stuheader.h文件,然後用stuims.c包含stufun.c文件,本覺得萬無一失,boom~boom~boom,error LNK2005來的如此突然、如此猛烈、瞬間呆若木雞。
二:原因分析
首先我們看向stufun.c文件中的函數頭,沒有加static、extern等關鍵字,所以所有的自定義函數都預設為外部函數(int menu_select、int enter等等);
接下來我們再來分析#include:文件包含預處理是指在文件編譯之前將源文件的全部內容包含進來(簡單的說就是將源文件的所有代碼copy過來代替該#include語句);
然後我們分析代碼:
- 在stuims.c 有語句:#include<stufun.c>。
- 被包含文件(stufun.c)中含有全局變數或外部函數(int menu_select、int enter等等)
這樣的話就導致項目中stufun.c有自定義函數的定義,而stuims.c中也有著一模一樣的自定義函數的定義,所以就出現了error LNK2005(重覆定義錯誤)
所以我們該怎麼改呢?
三:代碼修改
知道問題所在就簡單了,我存在的問題是項目中有多個外部函數定義導致重覆定義錯誤,所以我可以有兩種解決方法:
- 在stufun.c中的所有自定義函數頭處加extern關鍵字明確為外部函數,然後將#include "stufun.c"語句替換成#include "stuheader.h",No Error;
- 將stufun.c中的所有自定義函數頭部加static關鍵字明確其為內部函數,問題解決!
四:問題總結
出現這樣的問題在於做項目經驗太少,定義函數時沒有想到去添加其作用範圍,以後再定義全局變數和外部函數時一定謹慎謹慎再謹慎,一定要明確自己所定義的變數及函數的作用範圍,不然在軟體擴展時會出現意料之外的Bug。話已至此,還是非常感謝Bug2005,所以我決定:我——AboutSange和error2005在2016.04.09結為異性兄弟,一起去找尋成神路上尚未碰面的error!