c - C 中函数重载的替代方案

标签 c overloading variadic-functions

我正在寻找一种避免重写函数的优雅方法,其实现几乎相同,但只有签名(输入参数的数量及其数据类型)不同。我知道函数重载在 C 中是不可能的。我也知道可变参数函数的存在。但我认为它们在这种情况下不会有帮助。

考虑以下问题,我们需要计算三角形的面积。我们有两个函数实现两个不同的公式:S = 1/2bh 和 S = sqrt(s(s-a)(s-b)(s-c))。除了计算面积之外,每个函数还修改参数 nbnthr。最后,有一个顶层例程 bisect_area_... 对给定函数 area_tria1area_tria2 启动二分程序,针对参数对其进行优化nbnthr。目前我明确地实现了两个二分函数:一个用于 area_tria1 的签名,另一个用于 area_tria2。我觉得必须有一种更好、更优雅的方法,它允许有一个通用的二分函数 bisect_area_tria()。请注意,在我手头的真实案例中,输入参数数据类型也不同。

下面是函数签名的骨架伪代码:

// Calculate area of triangle, modify and return parameter 'nb'
void area_tria1_nb(..., int *nb, double b, double h, double *S) {

    // change parameter 'nb'
    ...

    S = 0.5*b*h;
}

// Calculate area of triangle, modify and return parameter 'nthr'
void area_tria1_nthr(..., int *nthr, double b, double h, double *S) {

    // change parameter 'nthr'
    ...

    S = 0.5*b*h;
}

// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr'
void bisect_area_tria1(..., double b, double h, double *S, int (*area_tria1)(double, double)) {
}

// Calculate area of triangle, modify and return parameter 'nb'
void area_tria2_nb(..., int *nb, double a, double b, double c, double *S) {

    // change parameter 'nb'
    ...

    S = sqrt(s*(s-a)*(s-b)*(s-c));
}


// Calculate area of triangle, modify and return parameter 'nthr'
void area_tria_2_nthr(..., int *nthr, double a, double b, double c, double *S) {

    // change parameter 'nthr'
    ...

    S = sqrt(s*(s-a)*(s-b)*(s-c));
}


// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr'
void bisect_area_tria2(..., double a, double b, double c, double *S, int (*area_tria2)(double, double, double)) {
}

void main() {

    bisect_area_tria1(..., &nb,   b, h, &S, area_tria1_nb);
    bisect_area_tria1(..., &nthr, b, h, &S, area_tria1_nthr);

    bisect_area_tria2(..., &nb,   a, b, c, &S, area_tria2_nb);
    bisect_area_tria2(..., &nthr, a, b, c, &S, area_tria2_nthr);

}

最佳答案

天真、简单的方法:

#include <stdio.h>

void func_int (int x) { printf("%d\n", x); }
void func_char (char ch) { printf("%c\n", ch); }

#define func(param)          \
  _Generic((param),          \
    int:  func_int,          \
    char: func_char)(param)  \
                    
int main() 
{
  func(1);
  func((char){'A'});
}

这是类型安全的,但只支持一个参数。乍一看,这似乎不够。

如果您想要完全可变的参数列表,那么您必须实现一种方法来解析可变参数宏和 __VA_ARGS__。可能,这是可能的。很可能是丑陋的。这可能不是您所需要的。

一般来说,函数重载的需要可能是“XY 问题”。您需要具有不同参数集的函数,并且您确信函数重载是解决它的最佳方法。因此,您问如何在 C 中进行函数重载。事实证明,这不一定是最好的方法。

更好的方法是使用单个结构参数创建一个函数接口(interface),它可以适应包含所有必要的参数。使用这样的接口(interface),您可以使用上述基于_Generic 的简单方法。类型安全且可维护。

关于c - C 中函数重载的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44631851/

相关文章:

c# - 如何检查 C# 中是否存在具有特定签名的方法?

c++ - C++ 中的重载运算符 -=

c++ - 从重载函数中提取返回类型

c - C 中的可变长度参数

c++ - 如何组合 lambda、可变参数函数和函数指针?

c - 从C中的一行中解析可变数量的不同类型的整数

c - valgrind 重新分配错误 : Conditional jump or move depends on uninitialised value(s)

c++ - 使用可变参数函数 C++

c - 为什么 while 写在这里没有 body ?

c - 查找最大数字在数组中出现的次数