they donβt know about βbest practices,β but the preprocessor was definitely the first thing that jumped at me. It is similar to templates in C ++.
[edit: and the answer of Jesus Ramos mentions different letters about functions with different types in libraries, and indeed, you probably want to do this]
you create a separate source file with your functions, everywhere you change it twice to FLOATING_POINT_TYPE (as an example), and then you include the source file from another file twice. (or any other method you choose, you just need to ultimately process the file twice, once with each data type as your definition.) [also to define a character added to distinguish between different versions of a function, define FLOATING_POINT_TYPE_CHAR]
#define FLOATING_POINT_TYPE double #define FLOATING_POINT_TYPE_CHAR d #include "my_fp_file.c" #undef FLOATING_POINT_TYPE_CHAR #undef FLOATING_POINT_TYPE #define FLOATING_POINT_TYPE float #define FLOATING_POINT_TYPE_CHAR f #include "my_fp_file.c" #undef FLOATING_POINT_TYPE #undef FLOATING_POINT_TYPE_CHAR
then you can also use a similar strategy for your prototypes in your headings.
but, therefore, in your header file you will need something like:
#define MY_FP_FUNC(funcname, typechar) \ funcname##typechar
and for function / prototype definitions:
FLOATING_POINT_TYPE MY_FP_FUNC(DoTheMath, FLOATING_POINT_TYPE_CHAR) ( FLOATING_POINT_TYPE Value1, FLOATING_POINT_TYPE Value2 );
etc.
I will definitely leave it to someone else to talk about the best methods :)
By the way, for an example of such a strategy in the mature piece of software, you can check out FFTW (fftw.org), although this is a little more complicated than the example, I think that it uses basically the same strategy.