27 9月 2007

[C/C++] 千萬別把function definition & 變數definition寫入.h裡

程式碼一多,為了撰寫與維護的方便,最好的方法就是將一個.cpp檔切割成多個檔案( .cpp & .h )
但是最近撰寫了一支程式,把它切成多個file,卻莫名其妙地出現了"multiple definition of [function name] ... "這種錯誤訊息...
我仔細地觀察了又觀察,不管是正著看、反著看、倒著看…都看不出錯誤來…正當對分檔的寫法失望之餘,想回復到原本一個檔案的寫法後,才驚覺原本寫法的漏洞與缺點…
原本的一個file寫到底的code....
#include<iostream>

void a_function(){
    int a;
}

void a_problem_function(){
    int problem;
}

int main(int argc, char**argv){
    return 0;
}
把它切成多個file... 包括 .h && .cpp
a.h的內容
#ifndef A_H
#define A_H

void a_function();

void a_problem_function(){
    int problem;
}

#endif
a.cpp的內容
#include "a.h"

void a_function(){
    int a;
}
main.cpp的內容
#include<iostream>
#include "a.h"

int main(int argc, char**argv){
    return 0;
}
compile過程:
% g++ -c a.cpp                                              
% g++ a.o main.cpp                                        
...... multiple definition of `a_problem_function()'

照上面的寫法實作後 會產生這樣的問題...
奇怪!? 明明a.h不是寫了「#ifndef ... #define .... 」怎麼還會有問題呢!?
沒錯! 這樣的寫法的確是會有問題的... 並不是說寫了「#ifndef ... #define .... 」,在compile過程中,就應該只有一份a_problem_function() 而不應該出現multiple definition的問題才對呀...
其實問題是在於g++ -c a.cpp後,產生了a.o檔,這個a.o檔裡面,已經包含了一個a_problem_function()的definition,然而接下來g++ a.o main.cpp時,main.cpp又去include a.h,因此,它又想產生了一份a_problem_function(),問題就此產生了!
所以把變數definition寫入.h檔也會產生一樣的問題喲!
所以問題的徵結就在於.h檔裡面,寫入了function的definition或是變數definition,這樣子容易在多個檔案互相include時,產生multiple definition的問題,所以說囉,千萬別偷懶…直接把function definition寫在.h檔裡,是很不明智的決定!!!

9 則留言:

匿名 提到...

大大,可以幫我看一下這個問題嗎?
c++的多重include
http://csie-tw.blogspot.com/2008/12/c-multiple-include.html

Unknown 提到...

在 C 中若使用到外部 func 可用 extern 告之.
例:
uart.h
----------
#ifndef _UART_H
#define _UART_H
extern unsigned char TXState;
extern void InitUart(void);
#endif //_UART_H

uart.c
----------
unsigned char TXState;
void InitUart(void)
{
...;
}

main.c
----------
#include "uart.h"
main()
{
TXState = 123;
InitUart();
}

但不知 C++ 可否有此關鍵字

Unknown 提到...

我的看法:
一般來講 .h 檔是要給別的程式用的
例如你的範例:
a.h 是要給 main.cpp #include 用
因此 a.cpp 就不用 #include 了
除非 a.h 裡有些定義是 a.cpp 沒有的
但 a.cpp #include "a.h" 時
可能會引發重複定義的問題
因此可能要避開, 例如:
a.h
----------
#ifndef A_H
#define A_H

#ifndef A_CPP
extern void a_function();
#endif
void a_problem_function(){ int problem; }
#endif

a.cpp
----------
#define A_CPP
#include "a.h"
void a_function(){ int a; }

以上看若有不對之處請指正, 謝謝!

Unknown 提到...

抱歉沒看清問題是出現在a_problem_function 的程式碼是寫在 a.h
又 a.h 被 #include 兩次, 所以就有兩份
a_problem_function 的程式碼啦! ^^
所以我前兩篇回的是文不對題啦! 請海函! ^^"

Falldog 提到...

Dear ak,
沒關係,我們觀念一致就好... XD
應該是我寫得太爛了,讓你看完後不能馬上了解我在說什麼...Orz..

Unknown 提到...

其實這邊只要 g++ a.cpp main.cpp 即可.
你之所以會錯是因為你是分開compile 2個.o檔
當你各自compile,當然都會各自把a_problem_function()把在.o檔裏
所以在link的時候就會在不同的.o看到相同的a_problem_function()...才會出錯

Falldog 提到...

Hi,
感謝你的見解,這的確是個方法可以解決這個問題
只是當project一大時,必須把某些module build成.lib檔,這時候就會可能會出錯了
所以我才覺得,以好的coding習慣而言,最好不要把 function or 變數的 definition 放在 .h
可以避免掉很多問題~

Unknown 提到...

我看了甚麼Orz

Unknown 提到...

This article expressed a wrong concept. It's better to separate implementations and definitions into header (.h) and implementation (.cpp) files.

To author,
I suggest you to make sure how to build a complexity project (using makefile), and, how to distribute your code as an library (as .so or .a). They are different.