I am trying to reduce code duplication in my C program, where all the statements in each branch of an if/else block are identical, except for a function name and its arguments. The idea is that the user specifies either x
, y
, or z
, and the program measures how long it takes to run either func_x
, func_y
, or func_z
1000 times.
More specifically, here is the high level design of the C code:
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// reading structs from a text file
struct dat_x read_dat_x_from_file(char *path);
struct dat_y read_dat_y_from_file(char *path);
struct dat_z read_dat_z_from_file(char *path);
// functions
int func_x(struct dat_x);
int func_y(struct dat_y);
int func_z(struct dat_z);
// runner computing runtime of func_x, func_y, or func_z
int main(int argc, char** argv) {
char *func_name = argv[1];
char *path = argv[2];
int a;
clock_t t;
if (strcmp(func_name, "x") == 0) {
struct dat_x args = read_dat_x_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_x(args);
}
t = clock() - t;
} else if (strcmp(func_name, "y") == 0) {
struct dat_y args = read_dat_y_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_y(args);
}
t = clock() - t;
} else if (strcmp(func_name, "z") == 0) {
struct dat_z args = read_dat_z_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_z(args);
}
t = clock() - t;
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
As you can see, in the main
function all the statements in each branch of the if-else block are identical; the only difference is that either func_x
, func_y
, or func_z
.
In a functional language, this pattern can be abstract by having a function run_timing_benchmark
which takes the func_*
and dat_*
arguments and hten runs the loop (possibly using polymorphism to define the signature of g
). While I can use function pointers in C, I can't write a polymorphic type signature.
What are suggestions for how to reduce the duplication in this program so that the timing code is only defined once? In practice I may have dozens of functions (not just x
/y
/z
) to benchmark using the same code, and the timing code may be more complex.
You can use a macro to generate the code. Since all the structures and functions follow a common naming scheme, you can use token pasting to generate them.
#define PROCESS(suffix, func_name_var, path_var, sum_var, time_var) \
time_var = time();
if(strcmp(func_name_var, #suffix) == 0) { \
struct dat_##suffix args = read_dat_##suffix##_from_file(path_var); \
for (int i = 0; i < 1000; i++) { \
sum_var += func_##suffix(args); \
} \
time_var = time() - time_var;
then you can use it like this:
PROCESS(x, func_name, path, a, t)
else PROCESS(y, func_name, path, a, t)
else PROCESS(z, func_name, path, a, t)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With