有关最近GCC编译出现的multiple definition问题
Published on 四月 27, 2010
最近在编译项目的时候,出现的multiple definition的错误。仔细排查了.h文件的define定义等,最后发现是自己定义类的时候写法有问题。因为这个问题浪费了很长时间,所以特别记在这里。
做测试如下:
新建一个目录firstdef,在其中创建文件firstdef.h,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #ifndef _FIRSTDEF_H_ #define _FIRSTDEF_H_ #include <iostream> #include <string> #include <vector> #include <map> using namespace std; class CFirstDef { public: void Show(); void Error(); void Test() { printf("Test\n"); } }; void CFirstDef::Show() { printf("OK\n"); } #endif |
对应建立firstdef.cpp,代码如下:
1 2 3 4 5 | #include "firstdef.h" void CFirstDef::Error() { printf("Error\n"); } |
对应编译成lib库的makefile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | SRC_DIR= ./ OBJ_DIR= ./ LIB_DIR= ./ OBJ_EXT= .o CXXSRC_EXT= .cpp CSRC_EXT= .c LIB_EXT= .a H_EXT= .h OBJECTS = $(OBJ_DIR)firstdef$(OBJ_EXT) LIB_TARGET = $(LIB_DIR)libfirstdef$(LIB_EXT) $(OBJ_DIR)%$(OBJ_EXT): $(SRC_DIR)%$(CXXSRC_EXT) @echo @echo "Compiling $< ==> $@..." $(CXX) $(INC) $(C_FLAGS) -c $< -o $@ $(OBJ_DIR)%$(OBJ_EXT): $(SRC_DIR)%$(CSRC_EXT) @echo @echo "Compiling $< ==> $@..." $(CC) $(INC) $(C_FLAGS) -c $< -o $@ all:$(LIB_TARGET) $(LIB_TARGET): $(OBJECTS) all: $(OBJECTS) @echo $(AR) rc $(LIB_TARGET) $(OBJECTS) @echo "ok" clean: rm -f $(LIB_TARGET) $(OBJECTS) |
编译结果如下:
rm -f ./libfirstdef.a ./firstdef.o Compiling firstdef.cpp ==> firstdef.o... g++ -c firstdef.cpp -o firstdef.o ar rc ./libfirstdef.a ./firstdef.o ok
之后在与firstdef目录平级的地方创建文件test.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <iostream> #include <string> #include <vector> #include <map> #include "firstdef.h" using namespace std; int main(int argc, const char *argv[]) { CFirstDef t; t.Show(); t.Error(); return 0; } |
makefile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | CXX = g++ TARGET = test C_FLAGS += -g -Wall LIB_FLAGS = INC=-I./firstdef LIB=-L./firstdef -lfirstdef all: $(TARGET) test: test.o $(CXX) -o $@ $^ $(LIB_FLAGS) $(LIB) $(C_FLAGS) .cpp.o: $(CXX) -c -o $*.o $(INC) $(C_FLAGS) $*.cpp .cc.o: $(CXX) -c -o $*.o $(INC) $(C_FLAGS) $*.cc clean: -rm -f *.o $(TARGET) |
编译结果如下:
rm -f *.o test g++ -c -o test.o -I./firstdef -g -Wall test.cpp g++ -o test test.o -L./firstdef -lfirstdef -g -Wall ./firstdef/libfirstdef.a(firstdef.o):firstdef.cpp:(.text+0xfe): multiple definition of `CFirstDef::Show()' test.o:E:\test\cpp\test_firstdefine\.\firstdef\firstdef.h|20| first defined here collect2: ld returned 1 exit status make: *** [test] Error 1
由此可见,对比Show和Test函数可以发现,Show报错而Test却没有报错。
对于公司同事说如果不用lib而是直接编译.o的话就不会出错,我单独测试了一下,makefile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | CXX = g++ TARGET = test C_FLAGS += -g -Wall LIB_FLAGS = INC=-I./firstdef #LIB=-L./firstdef -lfirstdef all: $(TARGET) test: test.o ./firstdef/firstdef.o $(CXX) -o $@ $^ $(LIB_FLAGS) $(LIB) $(C_FLAGS) .cpp.o: $(CXX) -c -o $*.o $(INC) $(C_FLAGS) $*.cpp .cc.o: $(CXX) -c -o $*.o $(INC) $(C_FLAGS) $*.cc clean: -rm -f *.o $(TARGET) |
编译结果如下:
rm -f *.o test g++ -c -o test.o -I./firstdef -g -Wall test.cpp g++ -o test test.o firstdef/firstdef.o -g -Wall firstdef/firstdef.o:firstdef.cpp:(.text+0xfe): multiple definition of `CFirstDef::Show()' test.o:E:\test\cpp\test_firstdefine\.\firstdef\firstdef.h|20| first defined here collect2: ld returned 1 exit status make: *** [test] Error 1
但是如果将Show设置为内联,则上面两种方法的编译就都没有问题了。
如:
1 | inline void Show(); |
有不少的教程都会将函数的实现写在头文件中,如此看来,还真是会给读者们造成许多误读啊。
另附:源代码下载,需要的朋友可以自己研究一下。
以上代码均在windows下g++ 3.4.5编译通过。
原创文章,版权所有。转载请注明:转载自Vimer的程序世界 [ http://www.vimer.cn ]
本文链接地址: http://www.vimer.cn/?p=1209
firstdef.h 里的 void Show() 应该写成 void CFirstDef::Show() 才是 CFirstDef 的成员函数,否则只是定义了一个普通的函数。
所以,之所以会有重复定义问题:firstdef.cpp 文件 include 了 firstdef.h 后,在 firstdef.o 里会产生一份 void Show()。而 test.cpp 文件 include 了 firstdef.h,编译生成的 test.o 里也有一份 void Show(),自然就 multiple definition 了。
[回复]
Dante 回复:
四月 28th, 2010 at 6:21 下午
这样一想的话,确实容易理解很多呢~ 呵呵
[回复]
Terrence 回复:
四月 28th, 2010 at 6:49 下午
对呀对呀,那个Show没加类作用域的嘛。
[回复]
赞成菜刀的说法,深入透彻。
[回复]
Dante 回复:
十月 6th, 2010 at 4:39 下午
嗯,确实如此,firstdef.h文件里面的那个show函数是我不小心写错了。。
[回复]