c preprocessor - Conditional Compilation in C for getting different versions of one function -


i asked myself if there nice way different versions of 1 function without copying whole source code. have different versions 1 one hand measuring execution time , on other hand writing intermediate result (for analytic purpose).

let me explain example: writing iterative solver solving linear system, in case gmres algorithm. measure runtime in 1 run , write residual @ every iteration step in different run. structure of program looks like:

//main.c  #include "gmres.h"  // setup arrays flag_print_res = 0; gmres(a,x,b,tol,maxtiter,flag_print_res); // reset arrays flag_print_res = 1; gmres(a,x,b,tol,maxtiter,flag_print_res); //.. 

and function:

//gmres.c  void gmres(double* a, double *x, double *b, double tol, int maxiter, int flag_print_res) {     // …     start_time = ((double) clock ())/clocks_per_sec;     for(iter=0; iter<maxiter; iter++)     {         // ...         if(flag_print_res)         {             fprintf(file, "%d %13.5e\n", iter, res);         }         // ...     }     end_time = ((double) clock ())/clocks_per_sec;     printf("execution time = %13.5e\n", end_time-start_time); } 

however, problem execution time is, evaluation if statement costs time, specially when evaluated every iteration. therefore question: how can create different version of function, in if statement evaluated @ compile time?

you can control settings @ compile time macros. used make 1 version of function available in build, however.

if want have both versions available in same program, must implement 2 different versions of function. preprocessor can avoid duplicating code.

multiple inclusion of separate implementation

one approach implement function in separate file gmres.c:

#ifndef gmres #error "gmres not defined" #endif  void gmres(double* a, double *x, double *b, double tol, int maxiter) {     (iter=0; iter < maxiter; iter++)     {         // ...          #ifdef gmres_print         fprintf(file, "%d %13.5e\n", iter, res);         #endif          // ...     } } 

and include file 2 sets of macros:

#define gmres gmres            // plain version #include "gmres.c" #undef gmres  #define gmres gmres_print     // printing version #define gmres_print           // set print flag #include "gmres.c" #undef gmres 

although #include commonly used include header files, can used include file, , here makes sense include *.c file. make sure don't have #pragma once or similar setting active. #error directive ensures name of function given macro.

compile separate objects

the same can achieved compiling same source file 2 separate objects:

cc -dgmres=gmres -o gmres.o -c gmres.c cc -dgmres_print -dgmres=gmres_print -o gmres_print.o -c gmres.c  cc -o gmres gmres.o gmres_print.o ... 

here, versions controlled via build control tool, e.g. makefile. must make sure there no duplicate symbols.

cheap template

another approach "cheap template" implement whole function macro:

#define gmres_impl(name, flag)                                       \ void name(double* a, double *x, double *b, double tol, int maxiter)  \ {                                                                    \     (iter=0; iter < maxiter; iter++)                             \     {                                                                \         // ...                                                       \                                                                      \         if (flag) fprintf(file, "%d %13.5e\n", iter, res);           \                                                                      \         // ...                                                       \     }                                                                \ } 

and implement 2 versions of different parameters:

gmres_impl(gmres, 0) gmres_impl(gmres_print, 1) 

you cannot have preprocessor directives in macro, control must via macro arguments. compiler can evaluate constant expressions if (0) , if (1) , eliminate dead code accordingly.

this approach may have uses, has 1 major drawback: error messages , debugging symbols refer line function implementation evoked gmres_impl, makes finding errors hard.


Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -