Почему эти макросы C не записаны как функции? - PullRequest
7 голосов
/ 23 августа 2011

Я изучаю код инструмента netstat (Linux), который AFAIK в основном читает файл /proc/net/tcp и довольно мило печатает из него.(Сейчас я сосредоточен на режиме -t.)

Я немного озадачен стилем кодирования, выбранным авторами:

static int tcp_info(void)
{
    INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)", tcp_do_one);
}

, где

#define INFO_GUTS6(file,file6,name,proc)                \
 char buffer[8192];                                     \
 int rc = 0;                                            \
 int lnr = 0;                                           \
 if (!flag_arg || flag_inet) {                          \
    INFO_GUTS1(file,name,proc)                          \
 }                                                      \
 if (!flag_arg || flag_inet6) {                         \
    INFO_GUTS2(file6,proc)                              \
 }                                                      \
 INFO_GUTS3

где

 #define INFO_GUTS3                                      \
  return rc;

и

#if HAVE_AFINET6
#define INFO_GUTS2(file,proc)                           \
   lnr = 0;                                              \
   procinfo = fopen((file), "r");                        \
   if (procinfo != NULL) {                               \
     do {                                                \
       if (fgets(buffer, sizeof(buffer), procinfo))      \
          (proc)(lnr++, buffer);                          \
     } while (!feof(procinfo));                          \
     fclose(procinfo);                                   \
   }
#else
#define INFO_GUTS2(file,proc)
#endif

и т. Д.

Ясно, что мой смысл кодирования наклоняется и говорит: «Это должны быть функции».Я не вижу никакой пользы от этих макросов.Это убивает читабельность и т. Д.

Кто-нибудь знаком с этим кодом, может пролить некоторый свет на то, что здесь происходит с «INFO_GUTS», и могла ли быть (или остается) причина такой странной кодировкиstyle?

Если вам интересно их использование, полный график зависимостей выглядит следующим образом:

#               /--->   INFO_GUTS1  <---\    
#  INFO_GUTS --*        INFO_GUTS2  <----*---- INFO_GUTS6
#      î        \--->   INFO_GUTS3  <---/           î 
#      |                                            |
# unix_info()              igmp_info(), tcp_info(), udp_info(), raw_info()

Ответы [ 4 ]

3 голосов
/ 23 августа 2011

Ваше ощущение, что "эти макросы должны быть функциями", мне кажется правильным;Я бы предпочел видеть их как функции.

Было бы интересно узнать, как часто используются макросы.Однако чем больше они используются, тем больше должна быть экономия места, если они являются реальной функцией, а не макросом.Макросы довольно большие и используют (по своей природе медленные) функции ввода-вывода сами по себе, так что использование макроса не ускорится.

И в наши дни, если вы хотите встроенную заменуфункции, вы можете использовать inline функции в C (как и в C ++).


Вы также можете утверждать, что INFO_GUTS2 должен использовать прямой цикл while вместо do ... while петля;он должен был бы проверить EOF только один раз, если бы он был:

while (fgets(buffer, sizeof(buffer), procinfo))
    (*proc)(lnr++, buffer);

Как и в случае ошибки (в отличие от EOF) в канале, код, вероятно, попадет в бесконечный цикл;fgets() потерпит неудачу, но feof() вернет false (потому что он не достиг EOF; обнаружена ошибка - см. ferror()), и цикл будет продолжен.Не особенно вероятная проблема;если файл откроется, вы редко получите ошибку.Но возможная проблема.

2 голосов
/ 25 августа 2011

Нет причин, почему. Человек, который написал код, вероятно, был очень смущен оптимизацией кода в целом и концепцией встраивания в частности. Поскольку компилятор, скорее всего, является GCC, есть несколько способов добиться встраивания функции, если для этой функции даже встраивание было необходимо, в чем я очень сомневаюсь.

Встраивание функции, содержащей вызовы файлового ввода-вывода, было бы то же самое, что брить слона, чтобы уменьшить его вес ...

1 голос
/ 25 августа 2011

Это выглядит как чья-то ужасная идея реализовать дополнительную поддержку IPv6. Вам придется пройтись по истории, чтобы подтвердить, но архив, кажется, возвращается только к 1.46, а подразумеваемый урон равен 1.20 +.

Я нашел архив git, возвращающийся к 1.24, и он все еще там. Старый код выглядит сомнительным.

Ни BusyBox, ни BSD-код не содержат такого грязного кода. Так что оно появилось в версии для Linux и сильно пострадало.

0 голосов
/ 25 августа 2011

Макросы генерируют код: когда он вызывается, все определение макроса раскрывается в месте вызова.Если, скажем, INFO_GUTS6 была функцией, она не смогла бы объявить, например, буферную переменную, которая впоследствии могла бы использоваться кодом, который следует за вызовом макроса.Пример, который вы вставили, на самом деле очень аккуратный: -)

...