Подсчет макросов препроцессора - PullRequest
9 голосов
/ 29 декабря 2011

У меня есть этот код макроса, который позволяет мне определять и перечисление C , и список перечисляемых имен в виде строк, используя одну конструкцию. Это не позволяет мне дублировать имена перечислителей (и, возможно, вносить ошибки в большие списки)

#define ENUM_DEFINITIONS(F) \
  F(0, Item1) \
  F(5, Item2) \
  F(15, Item3) \
  ...
  F(63, ItemN)

, то:

enum Items {
  #define ITEM_ENUM_DEFINE(id, name) name = id,
    ENUM_DEFINITIONS(ITEM_ENUM_DEFINE)
  #undef ITEM_ENUM_DEFINE

, который при расширении должен давать:

enum Items {
  Item1 = 0,
  Item2 = 5,
  Item3 = 15,
  ...
  ItemN = 63,
}

В файле реализации у меня есть этот код:

const char* itemNames[TOTAL_ITEMS];
int iter = 0;

#define ITEM_STRING_DEFINE(id, name) itemNames[iter++] = #name;
  ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
#undef ITEM_STRING_DEFINE

который при расширении производит:

itemNames[iter++] = "Item1";
itemNames[iter++] = "Item2";
itemNames[iter++] = "Item3";
...
itemNames[iter++] = "ItemN";

Я хотел бы знать, сколько элементов перечислителя я создал таким образом, и иметь возможность передавать его в массивы времени компиляции. В приведенном выше примере это будет определять, что TOTAL_ITEMS = N во время компиляции. Можно ли таким образом считать вызовы макросов?

Я видел упоминание о нестандартном макросе COUNTER , похожем на макросы FILE и LINE , но я надеюсь, что есть более стандартный способ.

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

Ответы [ 5 ]

8 голосов
/ 29 декабря 2011

Должно работать следующее:

#define ITEM_STRING_DEFINE(id, name) #name, // note trailing comma
const char *itemNames[] = {
  ENUM_DEFINITIONS(ITEM_STRING_DEFINE)
};

#define TOTAL_ITEMS (sizeof itemNames / sizeof itemNames[0])

Редактировать : Спасибо Раймонду Чену за то, что отметили, что нам не нужно беспокоиться о ненужной последней запятой в списке. (Я неправильно назвал проблему для перечислений со строгими компиляторами C89, как в Требуется ли последняя запятая в перечислении C? .)

4 голосов
/ 29 декабря 2011

Вы можете использовать ту же технику для подсчета вызовов.

enum itemscounter  { 
  #define ITEM_ENUM_DEFINE(id, name) name##counter,
    ENUM_DEFINITIONS(ITEM_ENUM_DEFINE) 
  #undef ITEM_ENUM_DEFINE 
 TOTAL_ITEMS
};
2 голосов
/ 29 декабря 2011

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

Вы всегда можете использовать язык сценариев, такой как ruby ​​или python, для создания файлов .c и .h. Если вы делаете это хорошо, вы можете интегрировать ваш скрипт в ваш Makefile.

1 голос
/ 29 декабря 2011

Я знаю, что это не полный ответ.Вы можете создать макрос вокруг чего-то вроде этого.

#include <stdio.h>

const char * array[] = {
  "arr1", "arr2", "arr3", "arr4"
};

int main (int argc, char **argv)$
{
  printf("%d\n", sizeof(array)/sizeof(const char *));
}

Если вы можете изменить свой enum, чтобы он содержал непрерывные элементы, вы можете сделать что-то вроде этого (из Boost)

enum { A=0,B,C,D,E,F,N };
const char arr[N]; // can contain a character for each enum value
0 голосов
/ 29 декабря 2011

См. Предложения Mu Dynamics 'Перечисления, строки и лень' ; по крайней мере, это связано с тем, что вы ищете.

В противном случае посмотрите на коллекцию Boost Preprocessor (которая может использоваться как с препроцессором C, так и с препроцессором C ++).

...