最后更新于 .

最近在编译项目的时候,出现的multiple definition的错误。仔细排查了.h文件的define定义等,最后发现是自己定义类的时候写法有问题。因为这个问题浪费了很长时间,所以特别记在这里。 做测试如下: 新建一个目录firstdef,在其中创建文件firstdef.h,代码如下:

#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,代码如下:

#include "firstdef.h"
void CFirstDef::Error()
{
    printf("Error\n");
}

对应编译成lib库的makefile如下:

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:

#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如下:

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如下:

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设置为内联,则上面两种方法的编译就都没有问题了。 如:

inline void Show();

有不少的教程都会将函数的实现写在头文件中,如此看来,还真是会给读者们造成许多误读啊。 另附:源代码下载,需要的朋友可以自己研究一下。 以上代码均在windows下g++ 3.4.5编译通过。

Pingbacks

Pingbacks已打开。

Trackbacks

引用地址

评论

  1. 瑞士菜刀

    瑞士菜刀 on #

    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 了。

    Reply

    1. Dante

      Dante on #

      这样一想的话,确实容易理解很多呢~ 呵呵

      Reply

      1. Terrence

        Terrence on #

        对呀对呀,那个Show没加类作用域的嘛。

        Reply

  2. zzg_china

    zzg_china on #

    赞成菜刀的说法,深入透彻。

    Reply

    1. Dante

      Dante on #

      嗯,确实如此,firstdef.h文件里面的那个show函数是我不小心写错了。。

      Reply

发表评论