Creating a common interface I have a sort of database with a many-to-many association between tags and files. For various reasons, I decided to forgo a junction table in favor of having the left and right tables store the associated values in the tables themselves. However I've ended up writing code like this:

GHashTable *tagdb_get_tag_files (tagdb *db, int tag_code)
{
    return g_hash_table_lookup(db-&gt;reverse, GINT_TO_POINTER(tag_code));
}

GHashTable *tagdb_get_file_tags (tagdb *db, int file_id)
{
    return g_hash_table_lookup(db-&gt;forward, GINT_TO_POINTER(file_id));
}

void tagdb_remove_tag (tagdb *db, int id)
{
    GHashTable *its_files = g_hash_table_lookup(db-&gt;reverse, GINT_TO_POINTER(id));
    if (its_files == NULL)
    {
        return;
    }

    GHashTableIter it;
    gpointer key, value;
    g_hash_table_iter_init(&amp;it, its_files);
    if (g_hash_table_iter_next(&amp;it, &amp;key, &amp;value))
    {
        tagdb_remove_tag_from_file(db, id, key);
    }
    g_hash_table_remove(db-&gt;reverse, GINT_TO_POINTER(id));
}

void tagdb_remove_file(tagdb *db, int id)
{
    GHashTable *its_tags = g_hash_table_lookup(db-&gt;forward, GINT_TO_POINTER(id));
    if (its_tags == NULL)
    {
        return;
    }

    GHashTableIter it;
    gpointer key, value;
    g_hash_table_iter_init(&amp;it, its_tags);
    if (g_hash_table_iter_next(&amp;it, &amp;key, &amp;value))
    {
        tagdb_remove_file_from_tag(db, id, key);
    }
    g_hash_table_remove(db-&gt;forward, GINT_TO_POINTER(id));
}


Where only a few identifiers change, but basically the same thing happens, just on different sides. Is there a simpler, less error prone way to do this in c? Maybe with macros?
You can pass a function that gets the correct object from tagdb.
AKA Service Locator pattern

typedef HashTable* (*ITEM_GETTER)(tagdb*);

HashTable* getTag(tagdb *db)  { return db-&gt;reverse;}
HashTable* getFile(tagdb *db) { return db-&gt;forward;}

GHashTable *tagdb_get_item_files (tagdb *db, int itemId, ITEM_GETTER getter)
{
    return g_hash_table_lookup(getter(db), GINT_TO_POINTER(itemId));
}

void tagdb_remove_item (tagdb *db, int id, ITEM_GETTER getter)
{
    GHashTable *its_files = g_hash_table_lookup(getter(db), GINT_TO_POINTER(id));
    if (its_files == NULL)
    {
        return;
    }

    GHashTableIter it;
    gpointer key, value;
    g_hash_table_iter_init(&amp;it, its_files);
    if (g_hash_table_iter_next(&amp;it, &amp;key, &amp;value))
    {
        tagdb_remove_tag_from_file(db, id, key);
    }
    g_hash_table_remove(getter(db), GINT_TO_POINTER(id));
}


Edit for clarity:

The old functions can now be implanted like this:

GHashTable *tagdb_get_tag_files (tagdb *db, int tag_code)
{
    return tagdb_get_item_files(db, tag_code, getTag);
}

GHashTable *tagdb_get_file_tags (tagdb *db, int file_id)
{
    return return tagdb_get_item_files(db, file_id, getFile);
}

void tagdb_remove_tag (tagdb *db, int id)
{
    tagdb_remove_item(db, id, getTag);
}

void tagdb_remove_file(tagdb *db, int id)
{
    tagdb_remove_item(db, id, getFile);
}