コンテンツにスキップ

最終更新:2026-10-12

オープンソース C++ コードの読み方

オープンソースプロジェクトのコードを瞬時に理解するには?

実際のプロジェクトやオープンソースコード、特に C コードはマクロを好んで使うため、大きな問題が起こります。コードの読解が非常に難しく、デバッグもまた別の問題です。大量のマクロを含むプロジェクトを渡されたとき、どうすれば素早く理解できるでしょうか?

面接ではよく、非常に重要な知識ポイントに出くわします。それは gcc のコンパイル過程です。皆さんはすらすら答えられるかもしれません。そこで候補者のレベルを区別するために、こんな質問が派生します:gcc のコンパイルパラメータをどれだけ知っていますか?各パラメータにはどのような役割があるでしょうか?前処理段階では何が起こるでしょうか?あなたは普段この段階で何をしますか?それはあなたにどのような役割があるでしょうか?

この節では、1 つのオープンソースプロジェクトを例に、コードをどう素早く理解するかを見ていきます!

以下は libev のコードの一部で、その中にいくつかのマクロがあります。例えば:

  • EV_FREQUENT_CHECK
  • assert
  • EV_P_
  • ANHE_w
  • ANHE_at_cache
void noinline
ev_timer_start (EV_P_ ev_timer *w) EV_THROW
{
  if (expect_false (ev_is_active (w)))
    return;

  ev_at (w) += mn_now;

  assert (("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.));

  EV_FREQUENT_CHECK;

  ++timercnt;
  ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1);
  array_needsize (ANHE, timers, timermax, ev_active (w) + 1, EMPTY2);
  ANHE_w (timers [ev_active (w)]) = (WT)w;
  ANHE_at_cache (timers [ev_active (w)]);
  upheap (timers, ev_active (w));

  EV_FREQUENT_CHECK;

  /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/
}

一瞬「何だこれ」となりませんか?このコードからはいくつかの疑問が浮かびます:

  • 関数のパラメータはいくつでしょう?
  • 関数の型は?
  • コード中の ev_at は何者でしょうか?

コードを瞬時に理解するために、-E を使って前処理段階でマクロ展開された後のコードを取得し、理解と読解を容易にします。

展開後、次のものが得られます:

void __attribute__ ((__noinline__))
ev_timer_start (struct ev_loop *loop, ev_timer *w)
{
  if (__builtin_expect ((!!((0 + ((ev_watcher *)(void *)(w))->active))),(0)))
    return;

  ((WT)(w))->at += ((loop)->mn_now);


# 3881 "ev.c" 3 4
 ((
# 3881 "ev.c"
 ("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.)
# 3881 "ev.c" 3 4
 ) ? (void) (0) : __assert_fail (
# 388libev: ev_timer_start called with negative timer repeat value\", w->repeat >= 0.)"
# 3881 "ev.c" 3 4
 , "ev.c", 3881, __PRETTY_FUNCTION__))
# 3881 "ev.c"
                                                                                            ;

  do { } while (0);

  ++((loop)->timercnt);
  ev_start (loop, (W)w, ((loop)->timercnt) + (4 - 1) - 1);
  if (__builtin_expect ((!!((((W)(w))->active + 1) > (((loop)->timermax)))),(0))) { int __attribute__ ((__unused__)) ocur_ = (((loop)->timermax)); (((loop)->timers)) = (ANHE *)array_realloc (sizeof (ANHE), (((loop)->timers)), &(((loop)->timermax)), (((W)(w))->active + 1)); ; };
  (((loop)->timers) [((W)(w))->active]).w = (WT)w;
  (((loop)->timers) [((W)(w))->active]).at = (((loop)->timers) [((W)(w))->active]).w->at;
  upheap (((loop)->timers), ((W)(w))->active);

  do { } while (0);


}

この時点でコードを理解するのはほぼ障害ありませんが、まだ十分に明快とは言えません。あなたと他の候補者との差を際立たせるため、いくつか質問を出しましょう:

  • 上には多くの行数が表示されていますが、取り除けますか?どう解決しますか?
  • 上の assert のようなシステムマクロは非常にシンプルで理解しやすく、展開する必要がありません。どうやるか分かりますか?
  • 上の 2 段階の展開では問題が発生する可能性があります。何が起きているか、どう解決するか分かりますか?

それでは、この節はここまでにします。次の節で続けて共有します。上の答えについて、ぜひコメント欄で議論しましょう!

関連トピック

コメント