如何编写一个返回未知类型数值数组之和的函数?

时间:2017-08-19 13:51:58

标签: c ubuntu

我需要编写一个函数来总结一个我不知道它的类型的数值数组。 该函数可以接收数组的大小和每个变量的大小。 我被告知我应该使用无效指针,但我不知道该怎么做。 顺便说一句,我不能使用宏。 谢谢!

1 个答案:

答案 0 :(得分:2)

说实话,整个练习听起来很愚蠢。

您需要使用具有与qsort()大致相似的界面的函数:

void calculate_sum(const void  *ptr,
                   const size_t size,
                   const size_t num,
                   void        *sum,
                   void       (*sum_func)(void *, const void *))
{
    size_t  i;
    for (i = 0; i < num; i++)
        sum_func(sum, (void *)((char *)ptr + size * i));
}

调用者仍然需要每种类型的求和函数,比如说

void sum_int(void *acc, const void *val)
{
    *(int *)acc += *(const int *)val;
}

void sum_float(void *acc, const void *val)
{
    *(float *)acc += *(const float *)val;
}

假设调用者有几个数组,比如

float  fdata[50];
double ddata[40];

要计算它们的总和,需要

float  fsum;
double dsum;

fsum = 0.0f;
calculate_sum(fdata, sizeof fdata[0], 50, &fsum, sum_float);

dsum = 0.0;
calculate_sum(ddata, sizeof ddata[0], 40, &dsum, sum_double);

该接口适用于qsort()之类的内容 - 尽管即使qsort()也可以从调用者能够传递第三个参数void *中获益,并将其用于比较函数。在我看来,排序练习对于这种界面非常有效,特别是当与某种小struct一起使用时。

在这里,我认为练习会使学习者走向错误的方向:这不是算术运算的正确接口。它产生的企业代码过于复杂和缓慢,专为工作安全而设计;不可读,可维护,良好的代码。

算术的东西,比如求和,在我看来需要专用函数。但这并不意味着您必须复制粘贴大量代码;我们可以在这里使用预处理器。

让我们看看如何使用C11 _Generic语义实现求和:

#include <stdlib.h>  /* For  size_t  type */

#define DEFINE_SUM_FUNC(type, funcname)             \
    type funcname (const type *data, size_t count)  \
    {                                               \
        const type  *ends = data + count;           \
        type         sum  = 0;                      \
        while (data < ends)                         \
            sum += *(data++);                       \
        return sum;                                 \
    }

DEFINE_SUM_FUNC(float,   float_sum);
DEFINE_SUM_FUNC(double, double_sum);
DEFINE_SUM_FUNC(short,   short_sum);
DEFINE_SUM_FUNC(int,       int_sum);
DEFINE_SUM_FUNC(long,     long_sum);

#define array_sum(array, count) _Generic((array)[0],                \
     float:  float_sum((const float  *)(array), (size_t)(count)),   \
    double: double_sum((const double *)(array), (size_t)(count)),   \
     short:  short_sum((const short  *)(array), (size_t)(count)),   \
       int:    int_sum((const int    *)(array), (size_t)(count)),   \
      long:   long_sum((const long   *)(array), (size_t)(count))  )

DEFINE_SUM_FUNC(type, funcname)宏评估函数定义。该函数计算数组元素的总和。 (此实现使用指针方法。)

现在,如果您拥有与以前相同的两个数组float fdata[50];double ddata[40];,则可以调用

fsum = array_sum(fdata, 50);
dsum = array_sum(ddata, 40);

请注意array_sum()适用于数组和指针。也就是说,如果您有float *fdata;const double *ddata;,则上述两行可以正常使用。

在C11之前的代码中,您可以删除array_sum()宏,并自行调用特定于类型的函数:

fsum = float_sum(fdata, 50);
dsum = double_sum(ddata, 40);

(GCC确实提供了一个__builtin_types_compatible_p()扩展程序,即使没有array_sum(),也可以用来构建_Generic()宏。)