zoukankan      html  css  js  c++  java
  • Error LNK2005 从敌人到朋友

    本人在写学生信息管理系统时遇到一个很头疼的错误——error LNK2005重复定义错误,苦思冥想百度谷歌bing之后都没能解决问题,于一清早刹那间觉得知道问题出在哪儿了,于是乎起床、开机、修改代码一气呵成,终于0 error(s) 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("按回车键回主菜单...
    ");
            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!

  • 相关阅读:
    iOS开发tips-UITableView、UICollectionView行高/尺寸自适应
    10559
    日志系统之基于Zookeeper的分布式协同设计
    IOS 图片上传处理 图片压缩 图片处理
    istream, outstream使用及常见错误
    matlab 扩大虚拟内存
    github不小心同步覆盖了本地文件
    经典统计语言模型
    Makefile 快速入门
    word2vec——高效word特征提取
  • 原文地址:https://www.cnblogs.com/sange3/p/5370988.html
Copyright © 2011-2022 走看看