We can also use macros for making code easier to read and write. For example we can implement macros for implementing the foreach
construct in C for some data structures like singly- and doubly-linked lists, queues, etc.
Here is a small example.
#include <stdio.h>
#include <stdlib.h>
struct LinkedListNode
{
int data;
struct LinkedListNode *next;
};
#define FOREACH_LIST(node, list) \
for (node=list; node; node=node->next)
/* Usage */
int main(void)
{
struct LinkedListNode *list, **plist = &list, *node;
int i;
for (i=0; i<10; i++)
{
*plist = malloc(sizeof(struct LinkedListNode));
(*plist)->data = i;
(*plist)->next = NULL;
plist = &(*plist)->next;
}
/* printing the elements here */
FOREACH_LIST(node, list)
{
printf("%d\n", node->data);
}
}
You can make a standard interface for such data-structures and write a generic implementation of FOREACH
as:
#include <stdio.h>
#include <stdlib.h>
typedef struct CollectionItem_
{
int data;
struct CollectionItem_ *next;
} CollectionItem;
typedef struct Collection_
{
/* interface functions */
void* (*first)(void *coll);
void* (*last) (void *coll);
void* (*next) (void *coll, CollectionItem *currItem);
CollectionItem *collectionHead;
/* Other fields */
} Collection;
/* must implement */
void *first(void *coll)
{
return ((Collection*)coll)->collectionHead;
}
/* must implement */
void *last(void *coll)
{
return NULL;
}
/* must implement */
void *next(void *coll, CollectionItem *curr)
{
return curr->next;
}
CollectionItem *new_CollectionItem(int data)
{
CollectionItem *item = malloc(sizeof(CollectionItem));
item->data = data;
item->next = NULL;
return item;
}
void Add_Collection(Collection *coll, int data)
{
CollectionItem **item = &coll->collectionHead;
while(*item)
item = &(*item)->next;
(*item) = new_CollectionItem(data);
}
Collection *new_Collection()
{
Collection *nc = malloc(sizeof(Collection));
nc->first = first;
nc->last = last;
nc->next = next;
return nc;
}
/* generic implementation */
#define FOREACH(node, collection) \
for (node = (collection)->first(collection); \
node != (collection)->last(collection); \
node = (collection)->next(collection, node))
int main(void)
{
Collection *coll = new_Collection();
CollectionItem *node;
int i;
for(i=0; i<10; i++)
{
Add_Collection(coll, i);
}
/* printing the elements here */
FOREACH(node, coll)
{
printf("%d\n", node->data);
}
}
To use this generic implementation just implement these functions for your data structure.
1. void* (*first)(void *coll);
2. void* (*last) (void *coll);
3. void* (*next) (void *coll, CollectionItem *currItem);