V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ilotuo
V2EX  ›  C

函数定义在头文件中,被编译进两个.o 却能正常链接和执行?

  •  
  •   ilotuo · 2015-07-16 11:11:45 +08:00 · 987 次点击
    这是一个创建于 3447 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这是源码:

    ```
    #ifndef __vtkOBJWriter_h
    #define __vtkOBJWriter_h

    class vtkOBJWriter : public vtkPolyDataAlgorithm
    {
    public:
    //...
    virtual int writeMtllib(std::ofstream &fout){};//这里被编译了两次(见编译警告),而且链接到同一个文件.但是没有报错..
    void setMtl(string s){// 同上
    mMtllibStr = s;
    }
    }

    /**
    int foo(){} //但是这个如果不注释的话不能编译.
    */

    #endif
    ```

    编译时,这个头文件被 main.cpp vtkOBJWriter.cxx include 却能编译.

    [ 25%] Built target Non-Rigid-Registar


    Scanning dependencies of target optimal_nonrigid_icp
    [ 50%] Building CXX object src/optimal_nonrigid_icp/CMakeFiles/optimal_nonrigid_icp.dir/vtkOBJWriter.cxx.o
    In file included from /Users/gerrie/repos/Non-Rigid-Registar/src/optimal_nonrigid_icp/vtkOBJWriter.cxx:29:
    /Users/gerrie/repos/Non-Rigid-Registar/src/optimal_nonrigid_icp/vtkOBJWriter.hpp:57:48: warning: control reaches end of non-void function
    [-Wreturn-type]
    virtual int writeMtllib(std::ofstream &fout){}; //这里被编译了两次(见编译警告),而且链接到同一个文件.但是没有报错..
    ^
    1 warning generated.
    [ 75%] Building CXX object src/optimal_nonrigid_icp/CMakeFiles/optimal_nonrigid_icp.dir/main.cpp.o
    In file included from /Users/gerrie/repos/Non-Rigid-Registar/src/optimal_nonrigid_icp/main.cpp:17:
    /Users/gerrie/repos/Non-Rigid-Registar/src/optimal_nonrigid_icp/vtkOBJWriter.hpp:57:48: warning: control reaches end of non-void function
    [-Wreturn-type]
    virtual int writeMtllib(std::ofstream &fout){}; //这里被编译了两次(见编译警告),而且链接到同一个文件.但是没有报错..
    ^
    1 warning generated.
    Linking CXX executable ../../bin/optimal_nonrigid_icp
    [100%] Built target optimal_nonrigid_icp


    但是nm 显示只有一个.o正真包含这个符号:

    O_O[11:03:07]release$ nm src/optimal_nonrigid_icp/CMakeFiles/optimal_nonrigid_icp.dir/vtkOBJWriter.cxx.o |grep writeMtllib
    0000000000005a20 S __ZN12vtkOBJWriter11writeMtllibERNSt3__114basic_ofstreamIcNS0_11char_traitsIcEEEE
    000000000000d680 S __ZN12vtkOBJWriter11writeMtllibERNSt3__114basic_ofstreamIcNS0_11char_traitsIcEEEE.eh
    0000000000005ab0 S __ZN14myVtkOBJWriter11writeMtllibERNSt3__114basic_ofstreamIcNS0_11char_traitsIcEEEE
    000000000000d700 S __ZN14myVtkOBJWriter11writeMtllibERNSt3__114basic_ofstreamIcNS0_11char_traitsIcEEEE.eh
    ^_^[11:03:16]release$ nm src/optimal_nonrigid_icp/CMakeFiles/optimal_nonrigid_icp.dir/main.cpp.o |grep writeMtllib
    O_O[11:05:19]release$

    这是怎么回事?所以是编译器自动优化,不编译第二个定义吗?
    3 条回复    2015-07-16 23:00:54 +08:00
    hitmanx
        1
    hitmanx  
       2015-07-16 13:48:13 +08:00
    按照c++标准,这不就是默认inline吗?
    xylophone21
        2
    xylophone21  
       2015-07-16 13:54:24 +08:00
    nm的时候加上 ”-CA"再贴一下。
    dahakawang
        3
    dahakawang  
       2015-07-16 23:00:54 +08:00   ❤️ 1
    放到头文件中定义的成员函数被include之后,在main.o和vtkOBJWriter.o中的确会有两个同名符号vtkOBJWriter::writeMtllib,但此种情况下,vtkOBJWriter::writeMtllib会被编译器置为weak symbol,所以后来linker看到两个同样的名字不会报错,只是随便选一个。

    同样在头文件中被include的template实现也有类似的机制。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   990 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:51 · PVG 02:51 · LAX 10:51 · JFK 13:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.