如何重用相同的 C 代码但使用不同的运算符
How to reuse the same C code but with different operators
我正在用 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 编程技术来处理这个问题?
块(闭包)在这种情况下有用吗?
我需要以某种方式重构代码吗?
你会如何解决这个问题?
使用一个函数代替运算符,该函数采用一些常量来定义函数的作用。这样你就可以用相同的方式构建很多逻辑,只改变函数的参数来决定函数中的实际 operation/s is/are。
一个或多个函数也可以是一系列重载,以帮助您避免重复过多的代码。请注意,您将必须重构代码以传入赋值(或非赋值)目标。
// 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;
}
// ...
}
请注意,对于这样的解决方案,唯一变得重要的 "shape" 是您的操作数。
经典的 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 的旧值
您尝试执行的操作看起来或多或少像地图操作。相反,我会定义一个函数 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;
}
我正在用 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 编程技术来处理这个问题?
块(闭包)在这种情况下有用吗?
我需要以某种方式重构代码吗?
你会如何解决这个问题?
使用一个函数代替运算符,该函数采用一些常量来定义函数的作用。这样你就可以用相同的方式构建很多逻辑,只改变函数的参数来决定函数中的实际 operation/s is/are。
一个或多个函数也可以是一系列重载,以帮助您避免重复过多的代码。请注意,您将必须重构代码以传入赋值(或非赋值)目标。
// 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;
}
// ...
}
请注意,对于这样的解决方案,唯一变得重要的 "shape" 是您的操作数。
经典的 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 的旧值
您尝试执行的操作看起来或多或少像地图操作。相反,我会定义一个函数 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;
}