Последнее обновление:2026-10-12
Как читать открытый C++-код¶
Как мгновенно понять код открытого проекта?¶
В реальных проектах и открытом коде, особенно в C-коде, очень любят использовать макросы, и это порождает большую проблему: читать такой код крайне сложно, а отладка — отдельная беда. Вам дают проект с огромным количеством макросов — как быстро в нём разобраться?
Обычно на собеседованиях встречается очень важная тема: процесс компиляции gcc. Многие отвечают на него без запинки, поэтому чтобы отличить уровень кандидатов, задают уточняющие вопросы: какие параметры компиляции gcc вы знаете и зачем нужен каждый из них? Что происходит на этапе препроцессинга? Что вы обычно делаете на этом этапе и чем это вам помогает?
В этом разделе на примере открытого проекта покажем, как мгновенно понять код!
Ниже приведён фрагмент кода 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 выше, очень просты и понятны, раскрывать их не нужно — знаете, как это сделать?
- На этих двух шагах раскрытия могут возникнуть проблемы — знаете, что происходит и как это исправить?
На этом пока всё, в следующем разделе продолжим делиться; ждём ваших ответов в комментариях!
Похожие темы¶
- Шесть способов разделения строк в C++ | C++那些事
- Заметки о разработке расширений CPython | C++那些事
- Памятка по разработке на C++ с libcurl | C++那些事
- Интересный фрагмент C++-кода | C++那些事
- Печать чисел от 1 до 100 без циклов в C++ | C++那些事