Search code examples
cfunctionmacrosc-preprocessorconditional-compilation

Right usage of ifdef to write the same function for different type of values, without writing it more than once


Im doing my homework, and I have hard time figuring out one thing. I'm suppose to write BST that can work with integer or with float. And for such and practicing we have different header files for integer, float and the tree itself.

I'm trying to create a way for a function to run based of which type I'm currently working with [int/float] without having to write it twice. so I got something like this:

void addItemToTree(BST* bst, void* val) 
{
#ifdef IsInt
    addItemToTreeRec(bst->head, *((int*)val));
#else
    addItemToTreeRec(bst->head, *((float*)val));
#endif
}

so far no problems, it leads to:

#ifdef IsInt
void addItemToTreeRec(node* my_node, int val)
#else
void addItemToTreeRec(node* my_node, float val)
#endif
{
-- function itself ---
}

but the problem is, the header file that contains all integer related struct and declaration do not recognize my function while the float header file does. I figured it has to do something with the way I lay the ifdef down but I cannot seems to solve it without having to copy the whole code and put it before #else


Solution

  • Note: Preprocessor macros expand before compilation. You can not change the function definition and invoke different versions of the function at run-time.


    If this is the thing you're looking for nonetheless, you can use #ifdef/#else directives in the parameter list to choose which type the second parameter should be without actually to define different functions:

    #define IsInt
    
    void addItemToTreeRec (node* my_node,        // Function declaration addItemToTreeRec. 
    #ifdef IsInt 
    int 
    #else
    float 
    #endif
    val
    );
    
    void addItemToTreeRec (node* my_node,        // Function definition addItemToTreeRec.
    #ifdef IsInt 
    int 
    #else
    float 
    #endif
    val
    )
    {
        #ifdef IsInt
        // Code if val is of type int.
        #else
        // Code if val is of type float.
        #endif
    }
    
    void addItemToTree ( BST* bst,           // Function declaration addItemToTree.
    #ifdef IsInt     
    int 
    #else            
    float 
    #endif 
    val
    );
    
    void addItemToTree ( BST* bst,           // Function definition addItemToTree.
    #ifdef IsInt     
    int 
    #else            
    float
    #endif 
    val
    )
    {
        addItemToTreeRec (bst->head, 
    #ifdef IsInt
        *((int*)val)
    #else
        *((float*)val)
    #endif
        );
    }
    

    Note: This is not necessary to be seen as subsequent code. You can bring the declarations into specific header files, as well as the definitions into different source files, but addItemToTreeRec needs to be at least forward declared before addItemToTree because it is used in addItemToTree.