Расширение макроса C99 для доступа членов Struct

Можно ли сделать проверку на недействительность и доступ в макросе?

Например:

#define LOG(mystruct, severity, format, ...) ({ \
  severity_t current = ERROR; \
  if (mystruct) { \
    current = mystruct->error_level; \
  } \
  if (severity >= current) { \
   ... //handle logging 
  } \
})

Если я позвоню с LOG(NULL, DEBUG, "test %s", "one"); Я получаю ошибку как таковую:

error: member reference base type 'void' is not a structure or union note: expanded from macro 'LOG' current = mystruct->error_level;

mystruct определяется как:

typedef struct mystruct_t {
  severity_t error_level;
}

Я хочу разрешить возможность работы с NULL mystruct, Например: случай, когда возникает ошибка при создании самой структуры.

2 ответа

Решение

Ваша проблема в том, что хотя первая ветка никогда не будет занята, NULL не имеет правильный тип, чтобы сделать ->error_level,

Вы можете избежать этого, указав правильный тип. Я бы сделал это с помощью локальной переменной, а не приведения, чтобы вы могли зафиксировать неправильные варианты использования вашего макроса. Просто добавь

yourType* myStr = mystruct;
current = myStr->error_level;

и ты должен быть в порядке.

Можно ли сделать проверку на недействительность и доступ в макросе?

Нет, препроцессор выполняет простую замену текста. Он не поддерживает условные выражения внутри определения макроса.

Когда вы используете макрос с LOG(NULL, DEBUG, "test %s", "one");четвертая строка расширяется до

current = NULL->error_level;

и с тех пор NULL обычно определяется как #define NULL ((void *)0), что далее расширяется до

current = ((void *)0)->error_level;

вот почему вы получаете сообщение о void не будучи структурой или союзом.


Чтобы решить проблему, не проходите NULL в макрос, передайте указатель, который содержит NULL к макросу, например

mystruct_t *ptr = malloc(...);
if ( !ptr )
    LOG( ptr, DEBUG, "no memory" );
Другие вопросы по тегам