С некоторой осторожностью вы можете сделать это довольно легко.Вам просто нужно точно определить, что вы сравниваете и настраиваете, и передавать их как макропараметры.Пример использования:
CHECK(obj1.a, obj2.d, bitmap, val1);
CHECK(obj1.b, obj2.e, bitmap, val2);
Предполагается, что CHECK
определено примерно так:
#define STRINGIFY(expr) #expr
#define CHECK(v1, v2, bitmap, bit) do \
{ if ((v1) != (v2)) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(v1 != v2)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
Вы, конечно, можете выложить макрос так, как вам нравится;Я не совсем доволен этим, но это не слишком ужасно.
Демонстрационный код
Компиляция и тестовый прогон:
$ gcc -Wall -Wextra -g -O3 -std=c99 xx.c -o xx && ./xx
failed check at 40: obj1.a != obj2.d
failed check at 42: obj1.c != obj2.f
bitmap - 5
$
Фактический код:
#include <stdio.h>
struct num
{
int a;
int b;
int c;
};
struct num1
{
int d;
int e;
int f;
};
enum type
{
val1 = 0,
val2 = 1,
val3 = 2,
};
#define STRINGIFY(expr) #expr
#define CHECK(v1, v2, bitmap, bit) do \
{ if ((v1) != (v2)) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(v1 != v2)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
int main(void)
{
struct num obj1 = { 1, 2, 3 };
struct num1 obj2 = { 2, 2, 4 };
int bitmap = 0;
CHECK(obj1.a, obj2.d, bitmap, val1);
CHECK(obj1.b, obj2.e, bitmap, val2);
CHECK(obj1.c, obj2.f, bitmap, val3);
printf("bitmap - %X\n", bitmap);
return 0;
}
Очевидно, этот код полагается на то, что вы сопоставляете правильные элементы и битовые числа в вызовах макроса CHECK.
Можно разработать более сложные схемы, используя offsetof()
и т. Д. И инициализированные массивыописание структур данных и т. д., но в итоге вы получите более сложную систему и мало пользы.В частности, вызовы не могут значительно уменьшить количество параметров.Вы можете предположить, что 'bitmap' - это переменная.Вам нужно идентифицировать два объекта, поэтому вы должны указать 'obj1' и 'obj2'.Где-то вдоль линии, вам нужно определить, какие поля сравниваются и бит для установки.Это может быть какое-то одно значение (возможно, число бит), но у вас все еще есть 3 аргумента (CHECK(obj1, obj2, valN)
и предположение о bitmap
) или 4 аргумента (CHECK(obj1, obj2, bitmap, valN)
без предположения о bitmap
), номного фоновой сложности и, вероятно, больше шансов ошибиться.Если вы можете повозиться с кодом так, чтобы у вас был один тип вместо двух типов и т. Д., То вы можете упростить жизнь с помощью гипотетической системы, но все же проще обрабатывать вещи, как показано в рабочем коде, я думаю.
Я согласен с gbulmer , что, вероятно, я бы так не поступил, но вы заявили, что значительно сократили размеры структур (за что, спасибо!) Иэто станет более заманчивым по мере увеличения числа полей (но я бы выписал сравнения только для одной пары типов структур в одной функции).
Вы также можете изменить макрос на:
#define CHECK(cond, bitmap, bit) do \
{ if (cond) \
{ printf("failed check at %d: %s\n", __LINE__, STRINGIFY(cond)); \
(bitmap) |= (1 << (bit)); \
} \
} while (0)
CHECK(obj1.a != obj2.d, bitmap, val1);
...
CHECK((strcmp(obj3.str1, obj4.str) != 0), bitmap, val6);
, где последняя строка показывает, что это позволит вам выбирать произвольные сравнения, даже если они содержат запятые.Обратите внимание на дополнительный набор скобок, окружающих вызов strcmp()
!