Расширение макроса 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" );