在C语言中的通用求和函数

3

在C语言中编写通用求和函数是否可行?

我试图编写一个可以处理任何数值类型的单个求和函数。

double sum(void* myArrayVoidPtr, size_t arrayLength, int arrayType){
    int i;
    double result = 0;

    //The goal is to make this next line depend on arrayType
    //e.g. if(arrayType == UINT16)
    unsigned short* myArrayTypePtr = (unsigned short*) myArrayVoidPtr;

    for(i = 0; i < arrayLength; i++){
        result += *myArrayTypePtr;
        myArrayTypePtr++;
    }
    return result;
}

4
可以,但不是这样做。 - haccks
“任意”数据不能作为double进行求和。同时,“任意”类型也无法使用+运算符。 - Eugene Sh.
将问题从“任意”更改为“任何数字”。 - manimino
3个回答

3
无法在C中创建通用函数。与C++不同,您没有模板。模板允许您创建多个版本的相同函数,这些版本根据它们“接受”的type(即-intfloat或任何class)而不同。这意味着该函数被编译了多次。
C没有模板,但您可以为此编写宏。这基本上相当于C++的模板,只是不太强大。但它将被“内联”,而不是一个真正的函数。
#define SUM(arr, len, sum) do { int i; for(i = 0; i < len; ++i) sum += arr[i]; } while(0);

int main(void) {
    int i_arr[] = {1,2,3};
    double d_arr[] = {1.5, 2.5, 3.5};
    int sum = 0;
    double d_sum = 0;
    SUM(i_arr, 3, sum)
    SUM(d_arr, 3, d_sum);
    printf("%d, %f\n", sum, d_sum);
    return 0;

}

输出:

6, 7.500000

为什么不可能?您可以创建一个通用函数。 - haccks
1
@haccks 你如何定义通用函数?在 C 中没有模板。你能做的最接近的事情是使用宏,或手动编写多个相同方法的实例。 - Mark Segal
1
你需要一个包含union和数据成员的结构体来表示数据类型。我现在没有时间,否则我会发布代码的。 - haccks
@haccks 不想催促你,但你现在有时间吗?我对你提到的通用实现很感兴趣。我会做类似这样的事情:https://gcc.godbolt.org/z/b3MMv6 - Ayxan Haqverdili

0

@Mark_Segal是正确的,不过我认为我有一个稍微更好的宏实现,它具有类似函数的返回值:

#define summation(arr, len) ({      \
    __typeof(*arr) sum = 0;         \
    for (int i = 0; i < len; ++i)   \
        sum += arr[i];              \
    sum; })

int main(void) {
    int   isum, iarr[] = { 1, 3, 7 };
    float fsum, farr[] = { 1.5, 3.2, 6.9 };
    isum = summation(iarr,3);
    printf("int sum: %d\n",isum);
    fsum = summation(farr,3);
    printf("float sum: %g\n",fsum);
    return(0);
}

输出:

int sum: 11
float sum: 11.6

这取决于__typeof运算符的存在(在GNU编译器中定义),在其他一些编译器中可以用没有前导下划线的typeof替换它。

0
如果您想使用函数来实现此操作,并且想要传递一个arrayType变量来确定如何访问数组(而不是使用typeof),那么可以尝试以下代码:
#include <stdio.h>
#include <stdint.h>

enum type_v {
    UINT8,
    UINT16,
    UINT32,
    UINT64,
    FLOAT,
    DOUBLE
};

union type_t {
    uint8_t*  uint8Array;
    uint16_t* uint16Array;
    uint32_t* uint32Array;
    uint64_t* uint64Array;
    float*    floatArray;
    double*   doubleArray;
};
    
double sum(void* voidArray, size_t arrayLength, int arrayType)
{
    union type_t arrays;

    switch(arrayType) {
        case UINT8:  arrays.uint8Array  = voidArray; break;
        case UINT16: arrays.uint16Array = voidArray; break;
        case UINT32: arrays.uint32Array = voidArray; break;
        case UINT64: arrays.uint64Array = voidArray; break;
        case FLOAT:  arrays.floatArray  = voidArray; break;
        case DOUBLE: arrays.doubleArray = voidArray; break;
    }

    int i;
    double result = 0;
    
    for(i = 0; i < arrayLength; i++){
        switch(arrayType) {
            case UINT8:  result += arrays.uint8Array [i]; break;
            case UINT16: result += arrays.uint16Array[i]; break;
            case UINT32: result += arrays.uint32Array[i]; break;
            case UINT64: result += arrays.uint64Array[i]; break;
            case FLOAT:  result += arrays.floatArray [i]; break;
            case DOUBLE: result += arrays.doubleArray[i]; break;
        }
    }
    return result;
}

int main()
{
    uint16_t array[] = {1,2,3,4};
    double result = sum(array, 4, UINT16);
    printf("Sum = %f\n", result);

    return 0;
}

在这里尝试:https://onlinegdb.com/1rjNYJGzg

请注意,虽然它是可扩展的到新类型,但它并不是真正的通用,因此您可以轻松地将其扩展到对数组中的结构体的单个成员求和。例如:

#include <stdio.h>
#include <stdint.h>

struct player {
    char name[32];
    int score;
};

enum type_v {
    UINT8,
    UINT16,
    UINT32,
    UINT64,
    FLOAT,
    DOUBLE,
    PLAYER
};

union type_t {
    uint8_t*        uint8Array;
    uint16_t*       uint16Array;
    uint32_t*       uint32Array;
    uint64_t*       uint64Array;
    float*          floatArray;
    double*         doubleArray;
    struct player*  playerArray;
};
    
double sum(void* voidArray, size_t arrayLength, int arrayType)
{
    union type_t arrays;

    switch(arrayType) {
        case UINT8:  arrays.uint8Array  = voidArray; break;
        case UINT16: arrays.uint16Array = voidArray; break;
        case UINT32: arrays.uint32Array = voidArray; break;
        case UINT64: arrays.uint64Array = voidArray; break;
        case FLOAT:  arrays.floatArray  = voidArray; break;
        case DOUBLE: arrays.doubleArray = voidArray; break;
        case PLAYER: arrays.playerArray = voidArray; break;
    }

    int i;
    double result = 0;
    
    for(i = 0; i < arrayLength; i++){
        switch(arrayType) {
            case UINT8:  result += arrays.uint8Array [i];       break;
            case UINT16: result += arrays.uint16Array[i];       break;
            case UINT32: result += arrays.uint32Array[i];       break;
            case UINT64: result += arrays.uint64Array[i];       break;
            case FLOAT:  result += arrays.floatArray [i];       break;
            case DOUBLE: result += arrays.doubleArray[i];       break;
            case PLAYER: result += arrays.playerArray[i].score; break;
        }
    }
    return result;
}

int main()
{
    struct player array[] = {{"Bob",1},{"MEl",2},{"Jim",3},{"Ann",4}};
    double result = sum(array, 4, PLAYER);
    printf("Sum = %f\n", result);

    return 0;
}

在这里尝试:https://onlinegdb.com/YfdFwKj0I


1
你将返回类型设置为 double,这不是很通用。 - Ayxan Haqverdili

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接