Daily Archive for June 19th, 2008

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の中で定義する、というふうにしています。

Google Code Jam 2008

Google – Code Jam に登録しておきました。 来月ですね!

前回とちがって、TopCoderのアプリを使うわけではなさそうです。 自分はRubyを言語として選んでみました。できるのかな。

2006年に挑戦し、自分のふがいなさを思い知らされ、 そこからTopCoderで練習を積んできました。 2年経ったいま、自分はちゃんと進歩しているのだろうか。

当時のエントリ:

仮想マシンのディスクイメージとTimeMachine

ひさびさにParallels上のWindowsを動かしたあとしばらくして、いつものようにTimeMachineが動きだした。でもなんかいつまでもかかってる。状況を覗いてみたら、5.6GB/7.8GBとか。なんだこれ。

ちょっと考えてみると、これは仮想マシンのディスクイメージに変更があったために、ファイルを丸ごとコピーしているからですね。ディスクイメージは巨大なファイルになりがちであり、仮想マシン内でのちょっとした変更でさえ、数GBのディスクコピーを生むことになります。差分バックアップとはどうみても相性が悪いですね。

んーむ。じゃあぼくがAppleで働くプログラマだったとして、この問題をどうやって解決するか考えてみます。

1: バイナリの差分をうまくとる

ふつうの解法。 バイナリファイルの差分を賢くとることのできるアルゴリズムがあればOK。 ぐぐってみると、たくさんありますね。Subversion, Rsyncでもつかわれている。 ただし、仮想マシンの中でのちょっとした変更でもディスクイメージの内容が大きく変わってしまうときつい。

2: 仮想ディスクの中身をケアした差分をとる

1の問題点を踏まえて。 ディスクイメージをマウントして、ディレクトリツリーのdiffをとる。 ディスクイメージのフォーマットを知っておく必要がありますね。


いいアイデアがないですね… これじゃAppleでは働き口がなさそうです。

仮想化が流行してくると、こうしたことも課題になってきそうです。 それとも、もう既に研究がすすんでいたりするものでしょうか。