Home > Back-end >  Is it possible to modularize C functions with different argument types?
Is it possible to modularize C functions with different argument types?

Time:07-14

I'm building a bTree to deal with 2 different file types.

struct bNode{
    char nodeType;
    int numKeys;
    Key key[MAX_KEYS 1];
    int desc[MAX_DESC 1];
};

struct bNode2{
    char nodeType;
    int numKeys;
    Key2 key[MAX_KEYS 1];
    int desc[MAX_DESC 1];
};

Each node has the especified struct as above. I would like to use the same function searchID() on both (instead of creating searchID2() for example).

int searchID(FILE *indexFile, struct bNode *node, int id){
    if(node->nodeType == LEAF){
        for(int i = 0; i < node->numKeys; i  )
            if(node->key[i].id == id)
                return node->key[i].rrn;
    }else{
        int i = 0;

        while(i < node->numKeys && id > node->key[i].id)
            i  ;
        if(id == node->key[i].id)
            return node->key[i].rrn;

        struct bNode *desc = readNode(indexFile, node->desc[i]);
        return searchID(indexFile, desc, id);
    }
    return -1;
}

Tried to implemented using void * but it didn't work at all.

CodePudding user response:

If you were to code something like the following example, I would think that you could get by with on structure definition but utilize two node variables in your code.

#include <stdio.h>
#include <stdlib.h>

#define MAX_KEYS 1000
#define MAX_DESC 1000
#define LEAF 'l'

typedef struct Kxx                                  /* Made this up for example purposes */
{
    int id;
    int rrn;
} Key;

struct bNode{                                       /* Just have one definition for the binary tree node */
    char nodeType;
    int numKeys;
    Key key[MAX_KEYS 1];
    int desc[MAX_DESC 1];
};

struct bNode * readNode(FILE *idxFile, int desc)    /* Made this up for example purposes */
{
    return NULL;
}

int searchID(FILE *indexFile, struct bNode *node, int id){
    if(node->nodeType == LEAF){
        for(int i = 0; i < node->numKeys; i  )
            if(node->key[i].id == id)
                return node->key[i].rrn;
    }else{
        int i = 0;

        while(i < node->numKeys && id > node->key[i].id)
            i  ;
        if(id == node->key[i].id)
            return node->key[i].rrn;

        struct bNode *desc = readNode(indexFile, node->desc[i]);
        return searchID(indexFile, desc, id);
    }
    return -1;
}

int main()
{
    struct bNode *bNode1;       /* In lieu of having two binary tree node structure definitions */
    struct bNode *bNode2;

    bNode1 = (struct bNode*)malloc(sizeof(struct bNode));
    bNode2 = (struct bNode*)malloc(sizeof(struct bNode));

    int result;

    FILE * file1 = fopen("tree_one.txt", "r");
    FILE * file2 = fopen("tree_two.txt", "r");

    result = searchID(file1, bNode1, 33);

    result = searchID(file2, bNode2, 759774);

    printf("Result test: %d\n", result);  /* Just printing so as to avoid an unused variable warning */

    return 0;
}

Please give that some consideration. There is no duplicate of the "bNode" structure. You could just define and allocate two node sets using "bNode". Hope that provides some food for thought.

Regards.

CodePudding user response:

You can use something like a template, implemented by macros. Then you will have two different types struct bNode_Key and struct bNode_Key2, and different functions to operate on each of them. Looks like you also need to template readNode.

#define TEMPLATE_bNode(T) \
struct bNode_ ## T { \
    char nodeType; \
    int numKeys; \
    T key[MAX_KEYS 1]; \
    int desc[MAX_DESC 1]; \
};

#define TEMPLATE_searchID(T) \
int searchID_ ## T(FILE *indexFile, struct bNode_ ## T *node, int id) { \
    ... \
    struct bNode_ ## T *desc = readNode_ ## T(indexFile, node->desc[i]); \
    ... \
}

#define TEMPLATE_readNode(T) \
int readNode_ ## T(FILE *indexFile, int desc) { \
    ...
}

TEMPLATE_bNode(Key1)
TEMPLATE_searchID(Key1)
TEMPLATE_readNode(Key1)

TEMPLATE_bNode(Key2)
TEMPLATE_searchID(Key2)
TEMPLATE_readNode(Key2)

However, if your T is supposed to consist of many tokens like in unsigned int, then the above simplified example will not work. Instead, you could distinguish between the name and the suffix like

#define TEMPLATE_bNode(T, SUFFIX) \
struct bNode_ ## SUFFIX { \
    ... \
    T key[MAX_KEYS 1]; \
    ...

and then use something like TEMPLATE_bNode(unsigned int, unsigned_int), which would result in the type name bNode_unsigned_int.

  • Related