Search code examples
cvariadic-macrosc-header

C header declaration for generics (macro)


I am unsure about where to write the declaration and the call of a macro that replaces the code with a function. I do not really know if I should write the macro to the .h or .c file. Before reading some stuff on the best ways to create libraries, I was just putting all the code in a header file and including it on my main, i.e.

#ifndef LIB
#define LIB
#define def_func(type)  \
  type func(type x)     \
  {                     \
    // Do something     
  }
  func(int)
#endif

Some other functions use these defined functions so I had to call the macro to the .h file.


Solution

  • Firstly, I think that a few small edits are needed in the code from the question:

    #ifndef LIB
    #define LIB
    #define def_func(type)  \
      type func(type x)     \
      {                     \
        /* Do something */  \
      }
      def_func(int)
    #endif
    

    The question does not detail what objective is being achieved, but I would assume that the goal is to create something that behaves like a template in C++, where the code is defined in one place and instances are created for different types by using the macro def_func.

    One thing to be aware of is if you are using def_func more than once in your project, then you are going to have linker errors due to the same global symbol being used in multiple places, even if def_func is used in separate files. This could be avoided by making the function static if def_func is used multiple times but never more than once in the same file. Although, this would restrict the function from being called from multiple files.

    Global symbol redefinition could also be avoided by adding another argument to the #define as follows:

    #define def_func(func, type) \
    type func(type x)            \
    {                            \
        /* Do something */       \
    }
    

    This would allow the function identifier to be specified uniquely. For example:

    def_func(func_int, int)
    

    would expand to:

    int func_int(int x)
    {                  
        /* Do something */
    }
    

    This way a unique identifier would be created for each instance.

    The #define should be placed in the header file if you intend to use the macro from multiple C source files. The macro should be used within C source files only, since using this in the header file would instantiate an object with the same global symbol in each case the header file is included. Although, this would be allowable if the functions are defined as static.

    Lastly, if you plan to call the function created from multiple locations, you will need a macro that can be used in a header file associated with the module defining the function to prototype the function. For example:

    #define def_func_proto(func, type) \
      type func(type x)
    

    So to sum it up, your library .h file would contain:

    #define def_func(func, type) \
    type func(type x)            \
    {                            \
        /* Do something */       \
    }
    
    #define def_func_proto(func, type) \
    type func(type x)
    

    Then using the integer case as an example, the C source file may include:

    def_func(func_int, int)
    

    Which would expand to (note that the actual expansion will not have line breaks):

    int func_int(int x)
    {                  
        /* Do something */
    }
    

    In this case, the header file may contain:

    def_func_proto(func_int, int);
    

    Which would expand to:

    int func_int(int x);
    

    Finally, I would note that am not certain that this is a good programming practice, in general. You will want to be very cautious in implementing this in your program.