c макрос для установки битов - PullRequest
0 голосов
/ 27 марта 2012

У меня есть программа, которая сравнивает переменные из двух структур и устанавливает бит соответственно для растровой переменной.Я должен сравнить каждую переменную структуры.Количество переменных в действительности больше для каждой структуры, но для простоты я взял 3. Я хотел знать, могу ли я создать макрос для сравнения переменных и установки бита в битовой карте соответственно.

#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,
};
int main()
{
  struct num obj1;
  struct num1 obj2;
  int bitmap = 0;

  if( obj1.a != obj2.d)
  {
      bitmap  = bitmap | val1;
  }
  if (obj1.b != obj2.e)
     bitmap = bitmap | val2;

  printf("bitmap - %d",bitmap);
  return 1;


}

Могу ли я объявить макрос как ...

#define CHECK(cond)
  if (!(cond))
    printf(" failed check at %x: %s",__LINE__, #cond);
    //set the bit accordingly

#undef CHECK

Ответы [ 4 ]

0 голосов
/ 27 марта 2012

Как разумное практическое правило, при попытке сделать битовые массивы - C, должен быть номер, который можно использовать для индексации бита.

Вы можете либо передать этот битовый бит в макрос, либо попытаться получить его.

Практически единственная доступная вещь во время компиляции или во время выполнения - это адрес поля.
Таким образом, вы могли бы использовать это.

Есть несколько вопросов, чтобы понять, может ли это сработать. Для ваших структур:

  1. Все поля в одном и том же порядке? То есть Вы можете сравнить C с F, а не C с E?
  2. Все ли соответствующие поля имеют одинаковый тип

Является ли условие просто равенством? Каждому макросу будет соответствовать условие, поэтому каждому условию нужен новый макрос.

Если ответ на все да, то вы можете использовать адрес:

#define CHECK(s1, f1, s2, f2) do \
    { if ((&s1.f1-&s1 != &s2.f2-&s2) || (sizeof(s1.f1)!=sizeof(s2.f2)) \
         || (s1.f1) != (s2.f2) \
         {   printf("failed check at %d: ", #s1 "." #f1 "!=" #s1 "." #f1 "\n", \
                                     __LINE__); \
             (shared_bitmap) |= (1 << (&s1.f1-&s1)); // test failed \
         } \
    } while (0)

Мне не очень понятно, является ли это растровым изображением для всех сравнений или по одному на пару структур. Я предположил, что это немного карта для всех.

Существует довольно много проверок, чтобы убедиться, что вы не нарушили «два правила»:

(&s1.f1-&s1 != &s2.f2-&s2) || (sizeof(s1.f1)!=sizeof(s2.f2))

Если вы уверены, что тесты будут правильными, без этих ограничений, просто отбросьте эту часть теста.

ПРЕДУПРЕЖДЕНИЕ Я не скомпилировал этот код.

Это становится намного проще, если значения являются массивом.

Я бы, наверное, не использовал его. Это кажется мне слишком сложным: -)

0 голосов
/ 27 марта 2012

С некоторой осторожностью вы можете сделать это довольно легко.Вам просто нужно точно определить, что вы сравниваете и настраиваете, и передавать их как макропараметры.Пример использования:

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()!

0 голосов
/ 27 марта 2012

Если вы хотите стать действительно причудливым (и кратким), вы можете использовать оператор конкатенации. Я также рекомендую немного изменить свои структуры, чтобы иметь разные соглашения об именах, хотя, не зная, что вы пытаетесь с этим сделать, сложно сказать. Я также заметил в вашем битовом поле, что у вас есть одно значение 0; это не скажет вам много, когда вы попытаетесь взглянуть на это значение бита. Если вы ИЛИ 0 во что-то, оно остается неизменным. В любом случае, ваша программа слегка переписана:

struct num {
   int x1; // formerly a/d
   int x2; // formerly b/e
   int x3; // formerly c/f
};

enum type {
   val1 = 1, // formerly 0
   val2 = 2, // formerly 1
   val3 = 4, // formerly 2
};

// CHECK uses the catenation operator (##) to construct obj1.x1, obj1.x2, etc.
#define CHECK(__num) {\
   if( obj1.x##__num != obj2.x##__num )\
     bitmap |= val##__num;\
}

void main( int argc, char** argv ) {
  struct num obj1;
  struct num obj2;
  int bitmap = 0;

   CHECK(1);
   CHECK(2);
   CHECK(3);
}
0 голосов
/ 27 марта 2012

Вы должны это сделать, за исключением того, что вам нужно использовать обратную косую черту для многострочных макросов

#ifndef CHECK
    #define CHECK(cond) \
    if (!(cond)) { \
      printf(" failed check at %x: %s",__LINE__, #cond); \
      //set the bit accordingly
    }
#endif /* CHECK */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...