使用预处理命令实现C的范型编程

一、引言

Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.
范型编程在1973年的ML语言中首次提出,是在C语言之后诞生的,你可以轻易的在C++/Java等语言里实现范型,但是C语言却没有提供实现范型的工具,使用C语言实现一组范型的函数需要使用一些技巧。
范型编程实现的一组函数会根据用户提供的不同类型进行实例化,在C语言中,我们能想到的就是使用预处理命令来达到这个效果。

二、预处理命令

在我的上一篇文章善用C语言预处理命令中,比较简单的介绍了预处理命令的一些使用技巧,我们在这里使用的是##符号。比如下面这个例子

#define GENERIC_FUNC(TYPE) \
           void func##TYPE() {...}

GENERIC_FUNC(int)
GENERIC_FUNC(float)

通过这种方式在代码中使用预处理的代码,根据不同的类型自动生成不同的代码,这就达到了范型编程的要求。

三、命名约定

使用这种技巧使得创建范型抽象数据类型成为可能,不过这种灵活性是需要付出代价的,使用者需要自己承担一些额外的责任。

  1. 采用一种命名约定,避免不同类型间的同样功能的函数发生冲突。
  2. 使用约定好的规则调用一组类型的函数,比如func_int() func_float()。
  3. 确保传入正确的数据类型。

四、一个范型的堆栈

/*
 * static array stack - generic implement
 */

#include <assert.h>

#define GENERIC_STACK(STACK_TYPE, SUFFIX, STACK_SIZE) \
    static STACK_TYPE stack##SUFFIX[STACK_SIZE];      \
    static int top_element##SUFFIX = -1;              \
                                                      \
    int is_empty##SUFFIX()                            \
    {                                                 \
        return top_element##SUFFIX == -1;             \
    }                                                 \
                                                      \
    int is_full##SUFFIX()                             \
    {                                                 \
        return top_element##SUFFIX == STACK_SIZE - 1; \
    }                                                 \
                                                      \
    void push##SUFFIX(STACK_TYPE value)               \
    {                                                 \
        assert(!is_full##SUFFIX());                   \
        top_element##SUFFIX += 1;                     \
        stack##SUFFIX[top_element##SUFFIX] = value;   \
    }                                                 \
                                                      \
    void pop##SUFFIX()                                \
    {                                                 \
        assert(!is_empty##SUFFIX());                  \
        top_element##SUFFIX -= 1;                     \
    }                                                 \
                                                      \
    STACK_TYPE top##SUFFIX()                          \
    {                                                 \
        assert(!is_empty##SUFFIX());                  \
        return stack##SUFFIX[top_element##SUFFIX];    \
    }

/*
 * test program for generic stack
 */

#include <stdio.h>
#include <stdlib.h>

GENERIC_STACK(int, _int, 10)
GENERIC_STACK(float, _float, 5)

int main()
{
    push_int(5);
    push_int(22);
    push_float(3.14);
    push_float(2.714);

    while(!is_empty_int()) {
        printf("Popping %d\n", top_int());
        pop_int();
    }

    while(!is_empty_float()) {
        printf("Popping %f\n", top_float());
        pop_float();
    }

    return EXIT_SUCCESS;
}

这种范型的堆栈对不同的类型创建了不同的静态数组用以表示堆栈空间,也可以看到代码中调用函数的约定规则,这些都是用户需要做的额外的工作。

五、结语

以上提供了一种在C中实现范型编程的解决方案,这种方案要求编写者与使用者提前约定好命名规则、函数调用规则,这些是获得充分的灵活性外必须要付出的代价。

猜你喜欢

转载自www.cnblogs.com/trav/p/9572042.html