C++でヘッダファイルに定義を書くかどうかで生成されるシンボルが変わる

不思議な現象に出くわしたので、エントリにしてみるテスト。

C++でプログラミングしていて、ヘッダにクラスのコンストラクタの定義を含めず、宣言だけを書くというのはよくあることだと思います。 次のようなヘッダファイルを考えてみます。

sym.h:

#ifndef _SYM_H_
#define _SYM_H_
class Sym {
public:
  Sym();
 
}; // Sym
#endif // _SYM_H_

実装は sym.cc に書きます。

#include "sym.h"
 
Sym::Sym() {
}
 
int main() {
  Sym sym;
  return 0;
}

これらをg++でコンパイルして、生成されるオブジェクトファイルを覗いてみると、驚きました。

% nm sym | c++filt
0000200c D _NXArgc
00002008 D _NXArgv
00001fde T Sym::Sym()
00001fd6 T Sym::Sym()
00002000 D ___progname
00001fc8 t __dyld_func_lookup
00001000 A __mh_execute_header
00002004 D _environ
         U _exit
00001fe6 T _main
00002010 d dyld__mach_header
00001fb4 t dyld_stub_binding_helper
00001f74 T start

なんで Sym::Sym()が2つ存在するんだ?

そして、ヘッダファイルに定義も含めると、1つになります。

#ifndef _SYM_H_
#define _SYM_H_
class Sym {
public:
  Sym() {}
}; // Sym
#endif // _SYM_H_
nm sym | c++filt
0000200c D _NXArgc
00002008 D _NXArgv
00001fb6 T Sym::Sym()
         U ___gxx_personality_v0
00002000 D ___progname
00001f90 t __dyld_func_lookup
00001000 A __mh_execute_header
00002004 D _environ
         U _exit
00001f9e T _main
00002010 d dyld__mach_header
00001f7c t dyld_stub_binding_helper
00001f3c T start

なぜだー。Mac OS X / Linux で確認しています。

使えるメモリが極めて限られている状況だと、こういう小さなところでも無駄は減らしたい。でもヘッダファイルに実装を書きまくるのは、できれば避けたいものです。

原因が分かるかたいらっしゃれば、ご教授ください ><


再現するためのコード一式を、symbols.zip に固めました。 Makefile中の CXXFLAGS += -DCOMPILE_BY_SPLIT のところを無効にするとヘッダファイルでコンストラクタの定義を行い、有効にすると.ccの中で定義する、というふうにしています。

  • ありがとうございます。


    なるほど、継承用にもつくられるのですか。自分は間違いなく継承はさせないんだけれど、そういう場合に2つつくられるのを抑制する方法がないものですかね。むー。

  • コンストラクタだけの話ですよね。


    shinhさんの所が、参考になるかと。
    http://d.hatena.ne.jp/shinichiro_h/20051015</p>

blog comments powered by Disqus