gpt4 book ai didi

C中的条件编译用于获取一个函数的不同版本

转载 作者:太空宇宙 更新时间:2023-11-03 23:24:18 25 4
gpt4 key购买 nike

我问自己是否有一种很好的方法可以在不复制整个源代码的情况下获得一个函数的不同版本。我希望有不同的版本,一方面用于测量执行时间,另一方面用于编写一些中间结果(用于分析目的)。

让我用这个例子来解释一下:我正在编写一个迭代求解器来求解线性系统,在我的例子中是 GMRES 算法。它想在一次运行中测量运行时间,并在不同运行中的每个迭代步骤写入残差。我的程序结构如下:

//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);
//..

和函数:

//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);
}

但是,执行时间的问题是,评估 if 语句会花费时间,尤其是在每次迭代都评估时。因此我的问题是:如何创建不同版本的函数,其中 if 语句在编译时求值?

最佳答案

您可以在编译时使用宏控制设置。但是,它们通常用于在构建中仅提供一个版本的函数。

如果您希望在同一个程序中同时使用两个版本,则必须实现该函数的两个不同版本。预处理器可以帮助您避免重复代码。

多重包含单独实现

一种方法是在单独的文件 gmres.c 中实现函数:

#ifndef GMRES
#error "GMRES not defined"
#endif

void GMRES(double* A, double *x, double *b, double tol, int maxiter)
{
for (iter=0; iter < maxiter; iter++)
{
// ...

#ifdef GMRES_PRINT
fprintf(file, "%d %13.5e\n", iter, res);
#endif

// ...
}
}

然后用两组宏包含该文件:

#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

虽然#include 通常用于包含头文件,但它可以用于包含任何文件,在这里包含*.c 文件是有意义的。确保您没有激活 #pragma once 或类似设置。 #error 指令确保函数的名称作为宏给出。

编译单独的对象

通过将同一个源文件编译成两个单独的对象可以实现同样的效果:

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 ...

在这里,版本是通过构建控制工具控制的,例如生成文件。您必须确保没有重复的符号。

便宜的模板

另一种方法是使用“廉价模板”将整个函数实现为宏:

#define GMRES_IMPL(NAME, FLAG)                                       \
void NAME(double* A, double *x, double *b, double tol, int maxiter) \
{ \
for (iter=0; iter < maxiter; iter++) \
{ \
// ... \
\
if (FLAG) fprintf(file, "%d %13.5e\n", iter, res); \
\
// ... \
} \
}

然后用不同的参数实现它的两个版本:

GMRES_IMPL(gmres, 0)
GMRES_IMPL(gmres_print, 1)

宏中不能有预处理器指令,因此必须通过宏参数进行控制。编译器可以评估常量表达式,如 if (0)if (1) 并相应地消除死代码。

这种方法可能有它的用处,但有一个主要缺点:所有错误消息和调试符号都引用使用 GMRES_IMPL 调用函数实现的行,这使得查找错误非常困难。

关于C中的条件编译用于获取一个函数的不同版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30827925/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com