Переменная no аргумента в макросе C - PullRequest
3 голосов
/ 16 февраля 2012

Я пишу некоторый аппаратный код, где я хочу использовать макросы C, определение макроса будет примерно таким: -

#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1) if(a[MODE][RESOURCE1] != x1) || \
                                                               (a[MODE][RESOURCE1] != y1)) \
                                                         a[MODE][RESOURCE1]=x3;

Поскольку иногда я могу выделить более 1 ресурса, например: -

#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) if(a[MODE][RESOURCE1] != x1) || \
                                                               (a[MODE][RESOURCE1] != y1)) \
                                                                         a[MODE][RESOURCE1]=x3;
                                                        if(a[MODE][RESOURCE2] != x1) || \
                                                               (a[MODE][RESOURCE2] != y1)) \
                                                         a[MODE][RESOURCE2]=x3;

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

Я использовал переменное число аргументов в макросе для макросов printf, но затем, как я буду обращаться к этим аргументам, по их соответствующему имени, например, если я изменю определение MACRO, например: 0-

#define VALIDA_RESOURCE_AND_ALLOCATE(MODE,.....) 

Как мне определить RESOURCE1, RESOURCE2?

Ответы [ 3 ]

1 голос
/ 22 февраля 2012

В ваших макросах много повторяющегося кода.Упрощение их помогает сделать решение более очевидным:

#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) do {\
    VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE1); \
    VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE2); \
} while(0)

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

Предполагая, что вы знаете,что используемые здесь типы данных всегда будут согласованы, вы можете попробовать что-то вроде этого (непроверенное и списанное из головы):

#ifdef HARDWARE_PLATFORM_A
  static sometype args[] = {
      RESOURCE1,
      RESOURCE2,
      /* ... etc, etc */
  };
#elif defined HARDWARE_PLATFORM_B
  static sometype args[] = {
      RESOURCE10,
      RESOURCE11,
      /* ... etc, etc */
  };
/* repeat for all hardware platforms */
#endif

void initialization_function (void) {
    int i;
    for (i = 0; i < (sizeof(args) / sizeof(args[0])); ++i) {
        VALIDATE_RESOURCE_AND_ALLOCATE(MODE, args[i]);
    }
}

, где sometype - это тип данныхаргументы, которые вы будете использовать для RESOURCE1, RESOURCE2 и т. д.

Учитывая сложность того, что вы пытаетесь сделать, вам было бы гораздо лучше написать функцию для выполнения итерации.макроса.Вы все еще можете использовать макрос для создания списка RESOURCE, но не пытайтесь заставить препроцессор выполнить итерацию за вас.Если вам нужно избежать издержек при вызове функции (поскольку вы пометили это как «встроенный»), вы можете объявить функции inline, и результат должен быть таким же эффективным, как и использование макроса.В процессе, однако, вы получите такие вещи, как безопасность типов.

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

Другая альтернатива, которую вы имеете, - это использовать генератор кода, который берет список из RESOURCE аргументов из файла и генерирует файл .cсодержащий код инициализации.Генератор кода будет написан на языке, намного более мощном, чем препроцессор C (здесь можно использовать практически любой язык сценариев).Это, вероятно, не стоило бы хлопот, если бы у вас не было длинного списка RESOURCE с.

0 голосов
/ 21 февраля 2012

Это было бы слишком глупо?; -)

#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1,RESOURCE2)                \
if(a[MODE][RESOURCE1] != x1) || (a[MODE][RESOURCE1] != y1))                     \
a[MODE][RESOURCE1]=x3;                                      \
if((RESOURCE1 != RESOURCE2) && (a[MODE][RESOURCE2] != x1) || (a[MODE][RESOURCE2] != y1)))   \
a[MODE][RESOURCE2]=x3;

и назовите его как показано ниже для одного ресурса

VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R1)

и как ниже для двух?

0 голосов
/ 16 февраля 2012

Один из способов сделать это - не передавать переменное число аргументов, а придерживаться двух и сделать второй список, который можно использовать при инициализации.Например (завершающие обратные косые черты для ясности прерваны):

#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE, LIST)
{
    int resources[] = LIST;
    int count;
    for(count = 0; count < sizeof(resources)/sizeof(int); count++) {
        /* do stuff here for each resources[count] */
    }
}

И затем вы можете просто назвать это так:

VALIDATE_RESOURCE_AND_ALLOCATE(MODE, { RESOURCE1, RESOURCE2 } )

Примечание: существует несколько способов скиновкот, так что выбирай свой любимый ответ и иди с ним: -)

...