Именование одноразовых идентификаторов глобальной области видимости - PullRequest
1 голос
/ 12 августа 2010

Иногда при использовании макросов для генерации кода необходимо создавать идентификаторы, которые имеют глобальную область видимости, но которые на самом деле бесполезны для чего-либо вне непосредственного контекста, в котором они создаются.Например, предположим, что необходимо скомпилировать во время компиляции массив или другой проиндексированный ресурс на куски разных размеров.

/* Produce an enumeration of some story-book characters, and allocate some
   arbitrary index resource to them.  Both enumeration and resource indices
   will start at zero.

   For each name, defines HPID_xxxx to be the enumeration of that name.
   Also defines HP_ID_COUNT to be the total number of names, and
   HP_TOTAL_SIZE to be the total resource requirement, and creates an
   array hp_starts[HP_ID_COUNT+1].  Each character n is allocated resources
   from hp_starts[n] through (but not including) hp_starts[n+1].
*/

/* Give the names and their respective lengths */
#define HP_LIST \
  HP_ITEM(FRED, 4) \
  HP_ITEM(GEORGE, 6) \
  HP_ITEM(HARRY, 5) \
  HP_ITEM(RON, 3) \
  HP_ITEM(HERMIONE, 8) \
  /* BLANK LINE REQUIRED TO ABSORB LAST BACKSLASH */

#define HP_ITEM(name, length) HPID_##name,
typedef enum { HP_LIST HP_ID_COUNT} HP_ID;
#undef HP_ITEM

#define HP_ITEM(name, length) ZZQ_##name}; enum {ZZQX_##name=ZZQ_##name+(length)-1,
enum { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#define HP_ITEM(name, length) ZZQ_##name,
const unsigned char hp_starts[] = { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#include "stdio.h"

void main(void)
{
  int i;

  printf("ID count=%d Total size=%d\n",HP_ID_COUNT,HP_TOTAL_SIZE);
  for (i=0; HP_ID_COUNT > i; i++) /* Reverse conditional to avoid lt sign */
    printf("  %2d=%3d/%3d\n", i, hp_starts[i], hp_starts[i+1]-hp_starts[i]);
  printf("IDs are: \n");
#define HP_ITEM(name, length) printf("  %2d=%s\n",HPID_##name, #name);
  HP_LIST
#undef HP_ITEMS

}

Существует ли какое-либо нормальное соглашение для именования таких идентификаторов, чтобы минимизировать вероятность конфликтов, итакже, чтобы минимизировать любую путаницу, которую они могут вызвать?В приведенном выше сценарии идентификаторы ZZQ_xxx будут такими же, как hp_starts [HPID_xxx], и могут быть полезны в некоторых контекстах, хотя их основная цель заключается в создании массива и в качестве заполнителей при вычислении других значений ZZQ и HP_TOTAL_SIZE.Однако идентификаторы ZZQX_xxx бесполезны;их единственная цель состоит в том, чтобы служить заполнителями при установке значений перечисления для последующих элементов.Есть ли хороший способ назвать такие вещи?

Кстати, я разрабатываю для небольших микроконтроллеров, где ОЗУ стоит дороже, чем пространство кода.Код моделируется путем компиляции в Microsoft VC ++, но для производства компилируется с использованием кросс-компилятора на прямом C;таким образом, код должен компилироваться как на C, так и на C ++.

Есть ли какие-либо другие приемы препроцессора, которые люди могут порекомендовать для подобных задач?

Ответы [ 2 ]

1 голос
/ 13 августа 2010

Существует ли какое-либо нормальное соглашение для присвоения имен таким идентификаторам, чтобы минимизировать вероятность конфликтов, а также минимизировать любую путаницу, которую они могут генерировать?

Все сводится к префиксу, который вы хотитеиспользовать.В идеале хотелось бы, чтобы все символы были легко связаны со списком (HP_LIST), с которым они связаны.

Так почему бы не поместить символы под одинаковым префиксом HP_?Например, префикс HP__ZZQX_, чтобы различать полезные и бесполезные символы.

Примечание. Я работал над проектом, в котором одна из общих библиотек уже использует (внутренне) префикс zzqx_, он всегда показывалвверх в таблице символов приложения в конце.В гонке за маловероятными для использования именами, очевидно, многие люди выбирают один и тот же маршрут (конец латинского алфавита) и получают точно такие же имена.Противоположность желаемого результата.Вот почему я думаю, что пространства имен (или в С префиксах символов) не должны быть скрыты / скрыты в определениях, а должны быть явно определены (например, легко найти и извлечь).

И как нечто конкретное, здесьВаш источник улучшен хаком вокруг ## для генерации имен с использованием префикса, заданного как определение препроцессора:


/* the hack is needed to force the LIST_NAME to be expanded. 
   automatically adds underscores. yes, it's ugly */
#define LIST_SYMBOL_1(n1,n2,n3) n1##_##n2##_##n3
#define LIST_SYMBOL_0(n1,n2,n3) LIST_SYMBOL_1(n1,n2,n3)
#define LIST_SYMBOL(pref,name)  LIST_SYMBOL_0(LIST_NAME,pref,name)

/* give the name to the list. used by the LIST_SYMBOL(). */
#define LIST_NAME   HP

/* Give the names and their respective lengths */
#define HP_LIST \
  HP_ITEM(FRED, 4) \
  HP_ITEM(GEORGE, 6) \
  HP_ITEM(HARRY, 5) \
  HP_ITEM(RON, 3) \
  HP_ITEM(HERMIONE, 8) \
  /* BLANK LINE REQUIRED TO ABSORB LAST BACKSLASH */

#define HP_ITEM(name, length) HPID_##name,
typedef enum { HP_LIST HP_ID_COUNT} HP_ID;
#undef HP_ITEM

#define HP_ITEM(name, length)   LIST_SYMBOL(ZZQ,name)}; \
    enum {LIST_SYMBOL(ZZQX,name)=LIST_SYMBOL(ZZQ,name)+(length)-1,
enum { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#define HP_ITEM(name, length) LIST_SYMBOL(ZZQ,name),
const unsigned char hp_starts[] = { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#include <stdio.h>

void main(void)
{
  int i;
  printf("ID count=%d Total size=%d\n",HP_ID_COUNT,HP_TOTAL_SIZE);
  for (i=0; i<HP_ID_COUNT ; i++) /* bring the < back, SO is smart enough */
    printf("  %2d=%3d/%3d\n", i, hp_starts[i], hp_starts[i+1]-hp_starts[i]);
  printf("IDs are: \n");
#define HP_ITEM(name, length) printf("  %2d=%s\n",HPID_##name, #name);
  HP_LIST
#undef HP_ITEMS
}

Редактировать 1.Мой предпочтительный подход заключается в том, чтобы поместить данные в правильный текстовый файл, например:

FRED
GEORGE
HARRY
RON
HERMIONE

(обратите внимание, что вам больше не нужна длина) и написать скрипт (или даже тривиальную программу на C) для генерации исходного кода.код из текстового файла, создание необходимого заголовка (с enum + декларация данных) и исходного файла (с данными).Измените Makefile для запуска скрипта перед компиляцией любых источников и добавьте сгенерированные исходные файлы в список скомпилированных источников.

Это имеет ОГРОМНОЕ преимущество в том, что сгенерированный код является простым кодом и можетбыть внесенным в указатель как таковой (если вы не любите забаву «откуда этот проклятый идентификатор?»).Внутренние константы просто больше не появляются в исходном коде, так как скрипт обрабатывает их.И никакой магии препроцессора больше нет.

0 голосов
/ 12 августа 2010

Вы можете проверить макросы препроцессора в проекте boost.У них умные препроцессорные счетчики.Вместе с __LINE__ вы можете использовать это для генерации уникальных идентификаторов, которые зависят только от строки, где они развернуты.Это может помочь вам избежать переопределения вашего макроса HP_ITEM.

...