2

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.

cigien
  • 57,834
  • 11
  • 73
  • 112
std124_lf
  • 134
  • 2
  • 9
  • 1
    One could do whatever one likes, but I would break them up, declaring `#define def_func(type)` in `.h` and `def_func(int)` to be more suited for `.c`. Make it an obvious name, like `def_func.h`. – Neil Oct 03 '21 at 01:39
  • You probably want a separate `decl_func` to use in headers. To expand the list, look into [x-macros](https://en.wikibooks.org/wiki/C_Programming/Preprocessor#X-Macros) – o11c Oct 12 '21 at 03:09

1 Answers1

0

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.

Jonathon S.
  • 1,928
  • 1
  • 12
  • 18
  • 1
    Not that `//` comments in macro bodies are basically undefined -- you can't use them safely as the following lines may or may not be pulled into the comment. – Chris Dodd Oct 03 '21 at 05:24
  • @ChrisDodd - Thanks for noticing. Converted `//` style comments to `/* */` style comments in these cases. – Jonathon S. Oct 03 '21 at 10:26
  • Thanks, before I hadn't created the proto macro, thus it gave me errors. The way of using as a parameter the name of the functions, I had already done, using the ## operator (I don't really know if that's an operator, looks like a concatenator). Anyways just a last question, if somehow i had to create a "template struct" I should just declare and call the macro in the header file, shouldn't I? Since I've seen people saying that we should declare public structs in the header file – std124_lf Oct 03 '21 at 11:23
  • Calling it directly in the header file will ensure that it is expanded in the same way each time the header file is included. If the macro is called in the source file, it will still recognize the type, but if there is a mistake, such as a copy and paste error, when placing the macro in the source file, you could run into some trouble. – Jonathon S. Oct 03 '21 at 11:28