这个问题的前言是,我意识到C宏是一个敏感的话题。很多时候,他们可以通过非宏观解决方案来实现,这种解决方案更安全,不会遇到经典问题,如增加的参数;所以在那里,我有一个散列表实现在C与链接节点的冲突。我相信大多数人已经看过这一百万次,但它有点像这样。这个foreach 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);
}
我能看到的唯一缺点是迭代器索引是表的一部分,所以显然你不能在同一个表中同时发生两个循环。我不知道如何解决这个问题,但我不认为这是一个交易断路器,考虑这个小宏观有多大用处。所以我的问题。
** 更新 **
我纳入扎克和Jens的建议,删除与“其他”,并宣布迭代里面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
是这种方法不好的形式,如果不是有什么办法改进呢?
我忍不住打量着邪恶博士。 “这是一个邪恶的宏?” – James 2011-02-18 16:02:06
难道你不能将迭代器传入宏吗?例如:tbleach(mytable,iterator,n)...这将允许您运行多个循环。 – Nick 2011-02-18 16:03:21