c - 在 if/else 中使用几乎相同的语句减少 C 程序中的代码重复?
问题描述
我试图减少我的 C 程序中的代码重复,其中 if/else 块的每个分支中的所有语句都是相同的,除了函数名称及其参数。这个想法是用户指定x
、y
或z
,然后程序测量运行func_x
、func_y
或func_z
1000 次所需的时间。
更具体地说,这里是 C 代码的高级设计:
// 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);
}
如您所见,在main
函数中,if-else 块的每个分支中的所有语句都是相同的;唯一的区别是func_x
,func_y
或func_z
.
在函数式语言中,这种模式可以通过一个函数来抽象,该函数run_timing_benchmark
接受func_*
anddat_*
参数并且 hten 运行循环(可能使用多态性来定义 的签名g
)。虽然我可以在 C 中使用函数指针,但我不能编写多态类型签名。
关于如何减少该程序中的重复以使时序代码只定义一次,有什么建议?在实践中,我可能有几十个函数(不仅仅是x
// y
)z
使用相同的代码进行基准测试,而且时序代码可能更复杂。
解决方案
一种想法可能是建立一个联合来抽象函数签名和返回值的差异。然后构建一个函数表并根据传递的名称调用正确的函数。像这样的东西:(警告:未经测试!)
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// Build a union that contains the structs
union uargs
{
struct dat_x;
struct dat_y;
struct dat_z;
};
// reading structs from a text file (but packaged into the union type)
union uargs read_dat_x_from_file(char *path);
union uargs read_dat_y_from_file(char *path);
union uargs read_dat_z_from_file(char *path);
// functions
int func_x(union uargs dat);
int func_y(union uargs dat);
int func_z(union uargs dat);
struct table_t
{
char *name;
union uargs (*read_dat_fp);
int (*fp)(union uargs dat);
};
// Table of function pointers
struct table_t func_table[]
{
{ "x", read_dat_x_from_file, func_x},
{ "y", read_dat_y_from_file, func_y},
{ "z", read_dat_x_from_file, func_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;
for(int i = 0; i < sizeof(func_table) / sizeof(table_t); i++)
{
if(strcmp(func_name, func_table[i].name) == 0)
{
union uargs args = func_table[i].read_dat_fp(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_table[i].fp(args);
}
t = clock() - t;
break;
}
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
这消除了代码重复,并且在某种程度上也很容易扩展。另一种选择可能是在@Barmar的这个答案中使用一些宏魔法。
编辑:当然,您可以简单地使用void*
和类型转换来传递指向结构的指针,而不是联合,在函数内部根据需要重新转换它们。但是你完全抛弃了所有类型检查。