Предисловие к этому вопросу заключается в том, что, как я понимаю, макросы C являются очень деликатным вопросом.Много раз они могут быть достигнуты не-макро-решением, которое является более безопасным и не подвержено классическим проблемам, таким как увеличенные аргументы;так что с этим из пути у меня есть реализация хеш-таблицы в C со связанными узлами для столкновения.Я уверен, что большинство из них видели это миллион раз, но это выглядит примерно так.
typedef struct tnode_t {
char* key; void* value; struct tnode_t* next;
} tnode_t;
typedef struct table_t {
tnode_t** nodes;
unsigned long node_count;
unsigned long iterator; // see macro below
...
}
Я хотел бы предоставить абстрактный способ итерации по узлам.Я подумал об использовании функции, которая берет указатель на функцию и применяет функцию к каждому узлу, но я часто нахожу такое решение весьма ограничивающим, поэтому я придумал этот макрос:
#define tbleach(table, node) \
for(node=table->nodes[table->iterator=0];\
table->iterator<table->node_count;\
node=node?node->next:table->nodes[++table->iterator])\
if (node)
, который можно использовать так:
tnode_t* n;
tbleach(mytable, n) {
do_stuff_to(n->key, n->value);
}
Единственный недостаток, который я вижу, - это то, что индекс итератора является частью таблицы, поэтому очевидно, что в одной и той же таблице нельзя одновременно выполнять два цикла.Я не уверен, как решить эту проблему, но я не рассматриваю это как прерыватель сделки, учитывая, насколько полезным будет этот маленький макрос.Итак, мой вопрос.
** updated **
Я включил предложение Зака и Йенса, убрав проблему с «else» и объявив итератор внутри оператора for.Кажется, все работает, но Visual Studio жалуется, что «имя типа не разрешено», где используется макрос.Мне интересно, что именно здесь происходит, потому что он компилируется и запускается, но я не уверен, где находится итератор.
#define tbleach(table, node) \
for(node=table->nodes[0], unsigned long i=0;\
i<table->node_count;\
node=node?node->next:table->nodes[++i])\
if (!node) {} else
Является ли этот подход плохим тоном, и если нет, то есть ли способ улучшить его