Error LNK2005 從敵人到朋友

来源:http://www.cnblogs.com/sange3/archive/2016/04/09/5370988.html
-Advertisement-
Play Games

本人在寫學生信息管理系統時遇到一個很頭疼的錯誤——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語句);

然後我們分析代碼:

  1. 在stuims.c 有語句:#include<stufun.c>。
  2. 被包含文件(stufun.c)中含有全局變數或外部函數(int menu_select、int enter等等)

這樣的話就導致項目中stufun.c有自定義函數的定義,而stuims.c中也有著一模一樣的自定義函數的定義,所以就出現了error LNK2005(重覆定義錯誤)

所以我們該怎麼改呢?

三:代碼修改

知道問題所在就簡單了,我存在的問題是項目中有多個外部函數定義導致重覆定義錯誤,所以我可以有兩種解決方法:

  1. 在stufun.c中的所有自定義函數頭處加extern關鍵字明確為外部函數,然後將#include "stufun.c"語句替換成#include "stuheader.h",No Error;
  2. 將stufun.c中的所有自定義函數頭部加static關鍵字明確其為內部函數,問題解決!

四:問題總結

出現這樣的問題在於做項目經驗太少,定義函數時沒有想到去添加其作用範圍,以後再定義全局變數和外部函數時一定謹慎謹慎再謹慎,一定要明確自己所定義的變數及函數的作用範圍,不然在軟體擴展時會出現意料之外的Bug。話已至此,還是非常感謝Bug2005,所以我決定:我——AboutSange和error2005在2016.04.09結為異性兄弟,一起去找尋成神路上尚未碰面的error!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • vs2012來做一個mvc3的項目,哪知在創建ado數據模型時跳出這麼一個東東 錯 誤: 此模板嘗試載入組件程式集 “NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a ...
  • 公司的一個項目由於管理和開發方面的一些問題,導致開發完成之後,一個js文件變的很大,minimize之後還有700kb, 影響了網站的性能,特別是在網速慢的時候,載入一個頁面居然要2分鐘。招來了一大堆的客戶投訴。。。 解決這個問題最理想的辦法是分解這個超大js文件,只載入所需的javascript。 ...
  • 已經可以對excel簡單的操作後 可以開始通過excel寫測試用例 讀取用例 執行用例 提前寫好execl 如圖: 下麵是代碼: 簡單的代碼寫好了 查看運行結果: 自己這個介面自動化測試框架的方向已經看到了 ...
  • 今天集中把幾種排序的方法列一下,當然最出名的希爾,快排,歸併和其優化當然也是滿載 說到希爾排序的話,不得不先提到的就是插入排序了,希爾排序就是對直接插入排序的一種優化,下麵就是直接插入排序的思想 這就是直接插入排序的代碼,思想很簡單,代碼也很簡單 為什麼希爾排序比直接插入排序更加優化呢?當需要排序的 ...
  • /*f(i,j)表示以(i,j)為右下角的最大全0子矩陣的邊長若a[i][j]==1,f(i,j)=0否則:f(i,j)=min{ f(i-1,j),f(i,j-1),f(i-1,j-1) }+1 這樣求得的是最大全0正方形子矩陣要求長方形矩陣,上述思路行不通假設以(i,j)為右下角的最大矩陣=12 ...
  • 編譯多個C源代碼文件 當程式文件越來越多,修改了其中的一部分代碼文件,我們並不需要全部重新編譯,只需要編譯其中一部分就可以,下麵我們創建了一個launch程式,除了主程式,我們創建了3個功能代碼文件reaction.c pitch.c engine.c 首先將源代碼編譯為目標文件 gcc -c *. ...
  • 對集合操作進行簡單的進行測試速度,數據量20w,對map,list,set,array,queue進行遍歷測試時間對比。 先粘貼一段對這些集合的介紹: 1.1 Set介面 1.2 List介面 1.3 Queue介面 1.4 Map介面 下麵是測試代碼: 時間:array:4ms,list:17ms ...
  • 一、源文件的編寫 Java是完全面向對象的語言,所以Java的所有操作都是基於類(class)完成的。Java中所有程式的代碼都需要放在一個類中,類用關鍵字class聲明,在class之前可以添加一些修飾符,Java應用程式的源文件由若幹個書寫形式相互獨立的類組成。 1.例子: (1)import語 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...