在C中采用未知类型参数的通用函数

时间:2018-04-23 15:32:23

标签: c generic-programming

我正在尝试制作一些函数,使用未知类型参数来泛化函数。

让我们举一个可以为数组的每个元素应用close(int fd)的函数:

void for_each(void *array[], void (*func)(void *))
{
    for (size_t i = 0; array[i] != NULL; ++i)
        func(array[i]);
}

如果我想将此函数与close(int fd)一起使用,我必须创建一个这样的包装函数:

void close_fd(void *fd)
{
    close(*(int *)fd);
}

我想将此for_each函数与字符串,浮点数和其他所有内容一起使用。

  
    
        
  • 没有包装部分,是不是可以实现它?
  •     
  • 我知道C ++有很多方法可以做到,lambdas,模板等,但在C中有一个好方法吗? 妥协
  •     
  

2 个答案:

答案 0 :(得分:1)

嗯,显然你想要为不同的数据多次调用一个函数(相同的函数)。但是这些数据是以数组形式传递的,根据定义,它是存储多个相同类型的 的数据项。所以最后没有特殊的构造可以做到这一点,只需在普通的C:

中进行
typedef .... MY_TYPE;

/* define a pointer to represent the type of callback pointer you are using */
typedef void (*callback_ptr)(MY_TYPE param);

/* this is the real callback function you are going to use */
void my_func1(MY_TYPE param){
    /* process a single MY_TYPE */
}

void my_funcN(MY_TYPE param) {
    /* another process function */
}

/* function to apply the callback to an array of MY_TYPE */
void for_each( MY_TYPE array[], size_t array_sz, callback_ptr f )
{
    int i;
    for (i = 0; i < array_sz; i++)
        f(array[i]);
}

....
MY_TYPE my_array[100] = { ... };
size_t my_array_sz = sizeof my_array / sizeof my_array[0];

for_each(my_array, my_array_sz, my_func1); /* process all by my_func1 */
for_each(my_array, my_array_sz, my_funcN); /* process all by my_funcN */

如果没有严格要求,请尽量避免使用void *。可能在早期设计阶段,您不知道它将要处理的实际数据类型,但很清楚,一旦您编写实际的调用语句,您必须输入参数并使用返回值,所以你坚持到实际的类型....这给你提供了如何声明回调指针和过程函数所需的提示。将实际类型放在函数调用中会使编译器检查是否正确,这有助于您避免犯错。

通用函数

C中不支持通用函数,但是如果你想要某种排列,允许你编写一些数据类型是通用的函数,你可以用宏来模拟它(你必须非常仔细地写宏来工作,但可以实现非常好的近似值)

您可以使用cpp宏为每种类型定义不同的函数,如:

func_def.h

#define FUNC(TYPE)                        \
        void my_func_##TYPE( TYPE param ) \
        {                                 \
          /* body of function */          \
        }

然后在文件范围中包含以下函数:

program.c

FUNC(int)
FUNC(double)

,这将扩展为:

        void my_func_int( int param )     \
        {                                 \
          /* body of function */          \
        }

        void my_func_double( double param ) \
        {                                   \
            /* body of function */          \
        }

无论如何,你都会在参数中进行类型检查。如您所见,您必须使用函数名称中的类型,因为C不支持函数的重载(具有相同名称和不同参数列表的函数)在这种情况下,my_func_*回调,并且必须定义for_each_*函数,以便编译器完全进行类型检查。

答案 1 :(得分:0)

如评论中所述,您可以使用宏来实现此目的。此外,在C语言中将数组的大小传递给使用它的函数更为惯用,而不是依赖于标记值(字符串是例外)。

#define for_each(array, array_size, func) do { \
    for (size_t i = 0; i < (array_size); ++i) { \
        func((array)[i]); \
    } \
} while(0)

用法:

#define ARRAY_SIZE(array) (sizeof((array)) / sizeof(*(array)))

void int_func(int arg)
{

}

void string_func(const char *arg)
{

}

int int_array[5];
const char *string_array[5];

void calling_func(void)
{
    for_each(int_array, ARRAY_SIZE(int_array), string_func); // Warning: pointer from integer without a cast
    for_each(string_array, ARRAY_SIZE(string_array), int_func); // Warning: integer from pointer without a cast
}