如何重用相同的C代码但使用不同的运算符

时间:2015-11-18 00:06:57

标签: c operators semantics code-reuse

我正在用C构建一个库,其中一个函数是库的一部分:

void myFunction(double *inPtr, double start, double step, double *outPtr, int N, t_shape shape)
{
    int i;

    switch (shape) {

        default:
        case ShapeLinear:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeExponential:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start;
                start *= step;
            }
            /* more stuff going on */
            break;

        case ShapeSquared:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeCubed:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start * start * start;
                start += step;
            }
            /* more stuff going on */
            break;
    }
}

这是一个简化版本,仅用于演示目的 库中的实际功能有更多的案例,每个案例都更长,更复杂。

现在我想创建完全相同功能的另一个版本,唯一不同的是,我想添加并分配将值分配给outPtr >它。

void myFunctionAdd(double *inPtr, double start, double step, double *outPtr, int N, t_shape shape)
{
    int i;

    switch (shape) {

        default:
        case ShapeLinear:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeExponential:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start;
                start *= step;
            }
            /* more stuff going on */
            break;

        case ShapeSquared:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeCubed:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start * start * start;
                start += step;
            }
            /* more stuff going on */
            break;
    }
}

正如我所说,我正在处理的实际功能更长,更复杂,所以不得不两次重写相同的代码,这是我不想做的事情。
这将是糟糕的编程实践,更难以维护。

是否有C编程技术来处理这个问题? 在这种情况下,块(闭包)是否有用? 我是否需要以某种方式重构代码?
你会如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

经典的c解决方案是传入一个被调用的函数来做你想要改变的事情。然而,这取决于操作的基本形状是相同的

typedef int (*func_ptr)(int,int); 
myFunction(....... func_ptr do_what)
{
int i;

switch (shape) {

    default:
    case ShapeLinear:
        /* more stuff going on */
        for (i = 0; i < N; i++) {
            *(outPtr++) = func_ptr(*(inptr++), outPtr);
            start += step;
        }
        /* more stuff going on */
        break;
}

int assign(int a, int b)
{
return a;
}

int add_assign(int a, int b)
{
return a + b;
}

然后致电

 myFunction(......assign);

myfunction(......add_assign);

因为我们必须传递outPtr的旧值

,所以感觉有点强迫你的情况

答案 1 :(得分:1)

您尝试做的事情或多或少看起来像地图操作。我会改为定义一个函数 Map 并用不同的输入函数调用它。以下是一个可编辑的例子。希望你可以扩展它以适应你的问题。

#include <assert.h>
#include <stdio.h>

#define LEN(array) (sizeof (array) / sizeof (array)[0])

typedef double (*Function)(double x);

static void Map(Function f, const double arr[], int arrLen, double result[], int resultLen)
{
    int i;

    assert(resultLen >= arrLen);

    for (i = 0; i < arrLen; i++) {
        result[i] = f(arr[i]);
    }
}


static double Square(double x)
{
    return x * x;
}


int main(void)
{
    double arr[] = {1.0, 2.0, 3.0, 4.0};
    double result[LEN(arr)];
    int i;

    Map(Square, arr, LEN(arr), result, LEN(result));

    for (i = 0; i < LEN(result); i++) {
        printf("%f\n", result[i]);
    }
    return 0;
}

答案 2 :(得分:0)

而不是运算符使用一个函数来获取一些常量来定义函数的作用。这样你就可以用相同的方式构造很多逻辑,只改变函数的参数来决定函数中的实际操作是什么。

一个或多个函数可以是一系列重载,以帮助您不重复过多的代码。请注意,您必须重构代码以传递分配目标(或非分配)。

// rough, simplistic, pseudo-codish example:

public void MyOperatorFunc(int opType, int var1, int var2, int* output) {
      if (opType == 1 ) {
          output = output + var1 + var2; 
      }
      else if (opType == 2) {
          output = var1 + var2;
      }
      // ...
 }

请注意,通过这样的解决方案,只有&#34;形状&#34;重要的是你的操作数。