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