Ir para o conteúdo

Última atualização:2026-10-12

Como ler código C++ open source

Como entender instantaneamente o código de projetos open source?

Em projetos reais ou em código open source, especialmente em código C, há grande apreço por macros — o que cria um problema enorme: ler o código fica muito difícil, e a depuração é outro problema. Diante de um projeto cheio de macros, como entendê-lo rapidamente?

Normalmente, em entrevistas, encontra-se um ponto de conhecimento muito importante: o processo de compilação do gcc. Talvez você responda de cabo a rabo; então, para diferenciar o nível dos candidatos, surgem desdobramentos: você conhece quais parâmetros de compilação do gcc e para que serve cada um? O que acontece na etapa de pré-processamento? O que você costuma fazer nessa etapa e de que ela te ajuda?

Nesta seção, tomando um projeto open source como exemplo: como entender o código num instante!

Abaixo está um trecho de código do libev, com diversas macros, por exemplo:

  • 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));*/
}
Parece meio desconcertante, não? Esse trecho levanta algumas perguntas:

  • Quantos parâmetros tem a função?
  • Qual é o tipo da função?
  • O que é o ev_at no código?

Para entender o código num instante, precisamos usar -E para obter o código da etapa de pré-processamento após a expansão das macros, facilitando o entendimento e a leitura.

Após a expansão, obteremos:

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);


}
Agora, entender o código praticamente não tem mais obstáculos, mas ainda não está claro o suficiente. Para destacar a diferença entre você e os outros candidatos, levanto algumas perguntas:

  • Acima aparecem muitas linhas de numeração; dá para removê-las? Como resolver?
  • Macros de sistema como o assert acima são muito simples e fáceis de entender, e não precisamos expandi-las — você sabe como fazer?
  • Nesses dois passos de expansão podem ocorrer problemas; você sabe o que acontece e como resolvê-los?

Bom, por enquanto é só isso nesta seção; na próxima continuo compartilhando. Seja bem-vindo a discutir as respostas acima na área de comentários!

Tópicos relacionados

Comentários