How evil is this foreach C macro? -
the preface question that, realize c macros touchy subject. many time can accomplished non-macro solution more secure , not subject classic problems incremented arguments; out of way, have hash table implementation in c linked nodes collision. i'm sure have seen million times goes bit this.
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 ... }
i provide abstracted way of iterating through nodes. considered using function takes function pointer , applies function each node find kind of solution limiting came macro:
#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)
which can used like:
tnode_t* n; tbleach(mytable, n) { do_stuff_to(n->key, n->value); }
the downside can see iterator index part of table not have 2 loops going on @ same time in same table. not sure how resolve don't see deal breaker considering how useful little macro be. question.
** updated **
i incorporated zack , jens's suggestion, removing problem "else" , declaring iterator inside statement. appears work visual studio complains "type name not allowed" macro used. wondering happens here because compiles , runs not sure iterator scoped.
#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
is approach bad form , if not there way improve it?
the unacceptable thing in there said -- iterator part of table. should pull out so:
typedef unsigned long table_iterator_t; #define tbleach(table, iter, node) \ ((iter) = 0, (node) = (table)->nodes[(iter)]; \ (iter) < (table)->node_count; \ (node) = ((node) && (node)->next) \ ? (node)->next : (table)->nodes[++(iter)]) // use: table_iterator_t i; tnode_t *n; tbleach(mytable, i, n) { do_stuff_to(n->key, n->value); }
i sucked if
statement for-loop expresssions because it's safer way (weird things not happen if next token after close brace of loop body else
). note array entry table->nodes[table->node_count]
will read from, unlike usual convention, need allocate space (and make sure it's null). true version well, think.
edit: corrected logic case table entry null.
Comments
Post a Comment