Я работаю над программой C. Существует функция, которая берет два аргумента указателя, назовите ее cmp()
. Я представляю здесь упрощенного заместителя для cmp()
по иллюстративным причинам:
int cmp(struct foo *a, struct foo *b)
{
return a->bar == b->bar;
}
Я хотел бы сделать макрос ПУСТОЙ проверки, как это:
#define SAFE_CMP(a,b) (((a) != NULL && (b) != NULL) ? cmp((a),(b)) : 0)
Я думаю, что это прекрасно подходит. Однако в при компиляции с обоими -Wall
и переключатель компиляции, который рассматривает предупреждение как ошибку, следующий код, неприятен:
int baz(struct foo *a)
{
struct foo b;
/* ... */
return SAFE_CMP(a, &b);
}
так как gcc предупреждает, что "адрес b никогда не будет ПУСТЫМ".
Там каким-либо путем является к обходному решению эта ситуация? Наличие различного макроса помощника как SAFE_CMP_1(safe_arg,unsafe_arg)
и SAFE_CMP_2(unsafe_arg,safe_arg)
и т.д. последняя вещь, которую я хочу. Я хотел бы иметь один макрос помощника, применимый ко всем ситуациям.
Кажется, это подавляет предупреждение для меня:
#define SAFE_CMP(a,b) (((void *)(a) != NULL && (void *)(b) != NULL) ? cmp((a),(b)) : 0)
... но лично я бы просто создал safe_cmp ()
как сама функция.
int safe_cmp(struct foo *a, struct foo *b) {
return (a && b) ? (a->bar == b->bar) : 0;
}
«Я хотел бы иметь один вспомогательный макрос применимо ко всем ситуациям. "
Почему? Один размер не подходит всем. GCC делает вам одолжение, сообщая вам, что сравнение всегда будет иметь определенный результат. Адрес переменной стека будет никогда не будет NULL. Я бы просто выписал проверку в baz:
int baz(struct foo *a) {
struct foo b;
...
return a == NULL ? 0 : cmp(a, &b);
}
Вы также можете сделать это в cmp
. Это зависит от того, как вы определяете предварительные и последующие условия.
Другая возможная проблема с вашим макросом (неприменима для baz) заключается в том, что a
и b
будут оцениваться несколько раз. Остерегайтесь:
SAFE_CMP(p++, p1++);
Параметр gcc -Wno-address
, похоже, удаляет предупреждения.