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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM