Может ли _Generic быть функцией? Или можно ли использовать _Generic с __attribute__((cleanup))?

Учитывая следующий исходный код:

#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>

static inline void closedirp(DIR **p) {
    if (*p)
        closedir(*p);
}

#define auto_cleanup(resource) _Generic((resource),     \
    DIR **: closedirp,                  \
        )(resource)

int main() {
#ifdef GENERIC
    __attribute__((cleanup(auto_cleanup))) DIR * t2 = NULL;
    t2 = opendir("/tmp");
#else
    __attribute__((cleanup(closedirp))) DIR * t1 = NULL;
    t1 = opendir("/tmp");
#endif
}

Он компилируется и работает без утечек, без определений. Однако, когда вы определяете GENERIC, компиляция завершается ошибкой:

$ gcc foo.c -DGENERIC
foo.c: In function ‘main’:
foo.c:16:2: error: cleanup argument not a function
  __attribute__((cleanup(auto_cleanup))) DIR * t2 = NULL;
  ^

Это довольно бессмысленное использование _Generic, однако я хотел расширить его и обрабатывать многие типы ресурсов для автоматической очистки.


person Dima    schedule 24.12.2014    source источник


Ответы (1)


_Generic — это не функция, а ключевое слово, с которого начинается первичное выражение.

Но здесь вы, похоже, еще больше ошиблись: auto_cleanup — это макрос. Функции, подобные макросам, имеют особенность, заключающуюся в том, что они не расширяются, если после них не идет (). Так что здесь вы просто сохраняете идентификатор auto_cleanup для более поздних этапов компиляции. Но этот идентификатор ничего не объявляет для этих более поздних фаз.

Обобщить:

  • ваш макрос, если он используется правильно, будет текстуально заменен на очень ранней стадии компиляции
  • затем более поздние фазы увидят выражение _Generic и решат, какая ветвь этого выражения _Generic будет взята
  • только эта ветвь "выживет" и будет скомпилирована в этой части кода

Во всем этом нет ни одной функции или указателя на функцию, которые можно было бы использовать для расширения gcc cleanup.

person Jens Gustedt    schedule 24.12.2014