zoukankan      html  css  js  c++  java
  • multiple definition of XXX情况分析

    近日在写代码,各个.cpp源文件编译时没有问题,将*.o进行链接时,出现了许多multiple definition of XXX的链接错误。于是在网上搜索了一番,结合自己的代码包含逻辑,最终发现了问题,记载如下:

    一、问题描述:

    Threadpool.h:

    声明了一些函数原型和一些全局变量,这些标示符是没有带extern关键字的。

    Threadpool.cpp:

    该cpp文件对Threadpool.h中函数进行定义,变量给出初始值。

    单独编译g++ -g  -c  Threadpool.cpp不会有问题。

    Main.cpp:

    我在Main.cpp中需要用到Threadpool.cpp中定义好的函数以及变量,所以我在Main.cpp中#include "Threadpool.h"。

    单独编译g++ -g  -c  Main.cpp 也没有问题。

    当进行链接时:g++ -o Main Threadpool.o Main.o  -lpthread

    就会出现:multiple definition of XXX

    二、题产生的原因:

    C/C++中一个.c和.cpp文件以及其include到的头文件称为一个编译单元,该单元是独立编译的。一个标示符可以多次声明,但是只能够定义一次。

    为什么Threadpool.cpp和Main.cpp都包含Threadpool.h,在链接阶段会出现重复定义的符号呢?真正的问题出在头文件标示符。

    Threadpool.h:

    int  a;

    double d;

    int fnu();

    //etc

    在Threadpool.cpp中#include时被预处理器处理之后,出现了一次定义。

    int  a;

    double d;

    int fnu();

    在Main.cpp中#include同样被预处理器处理之后:再一次出现了定义。

    int  a;

    double d;

    int fnu();

    为什么编译阶段不会出现问题呢?

        执行g++ -g  -c  Threadpool.cpp时,对应的.cpp文件将会被编译成目标文件,目标文件含有一系列Threadpool.h中定义过的标示符。

    执行g++ -g  -c  Main.cpp时,对应的.cpp文件也将会被编译成目标文件,目标文件同样含有一系列Threadpool.h中定义过的标示符。

    上述二者被独立的编译成目标文件,所以编译不会有问题。

    我们可以这样想象-c每一个源文件时,相当于一条有管道包围的纵向水流,二者互不干扰。当-o链接时两条原本相互独立的水管横向流了,所有就出现了重复的元素。所以当进行链接时:g++ -o Main Threadpool.o Main.o  -lpthread。就会出现重复定义的标示符。重复定义的标示符在这里只是变量,函数不会。因为函数确实只在.cpp中定义了一次,多次声明是没有问题的,而变量确实出现了两次定义。

    三、我的解决方案:

        不在头文件中定义全局变量,头文件中只含有函数的原型声明,而将所有的全局变量放入Threadpool.cpp中,当Main.cpp需要用到这些全局变量时,extern一下,告诉编译器这些变量是在其他源文件中定义的。

    得到的启示:

    (1)最好不要在头文件中定义全局变量。

    (2)在C/C++中分清楚标示符的声明(declared)和定义(definition)的区

             别很重要。

    (3)该问题与没有用#ifndef,#define,#endif产生问题的原因是不一样的。

    非常好的一篇blog,我在写代码的时候也碰到了类似的问题,其实也是全局变量和函数的重复定义的问题!!!但是我的例子比较复杂,不好描述,而作者的例子清晰易理解,故转载过来。另外这篇文章最令我受益的一句话是:

    C/C++中一个.c和.cpp文件以及其include到的头文件称为一个编译单元,该单元是独立编译的。一个标示符可以多次声明,但是只能够定义一次。

    文章转载自:http://blog.csdn.net/luo6620378xu/article/details/8511312

  • 相关阅读:
    关于idea的目录, mybatis里mapper无法用resource获取 和 驼峰命令规则
    直接调用类方法 和 new再调用方法 的区别
    腾讯笔试题
    linux安装包
    centos 学习笔记一
    putty链接l虚拟机linux centos
    单链表的一般处理(C语言)
    华为2011机试题
    【转】函数返回类型为指针类型时的一些问题
    在 Windows Server 2012 上安装 dotNET Framework v3.5
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/9335795.html
Copyright © 2011-2022 走看看