如何使 C 函数与数据类型无关

How to make C functions agnostic to data type

我一直在用 C 编写一个简单的库来处理数组、动态数组和链表。作为起点,我一直在研究从数组中弹出用户定义索引的函数。对于初学者,我正在处理一个整数数组并找到了这个解决方案。

int pop_int_array(int *array, int index, int size) {
    int type = sizeof(int);
    if (index >= size) return 0;
    unsigned char *dst = (unsigned char*) array + index + type;
    memmove(dst, dst + type, type * (size - index - 1));
    return 1;
}

int main(int argc, const char * argv[]) {
    int a[5] = {1, 2, 3, 4, 5};
    pop_int_array(a, 2, 5);
    for (int i = 0; i < 4; i++) {
        printf("%d\n", a[i]);
    }
}

这将按预期产生以下输出

1
2
4
5

如果我想弹出一个 float 数组,我需要创建一个名为 pop_float_array 的新函数来复制 pop_int_array 中的所有内容,而不是使用 int type = sizeof(int) 我会用 int type = sizeof(float) 替换它,当然数组数据类型将是 float 而不是 int。但是,这违反了软件开发的核心原则,因为多次重复相同的代码,而每次都是一种数据类型的实现。为了解决这个问题,我按照以下方式重新编写了函数,其中数组被声明为 void 数据类型。此外,在将数组传递给函数之前或过程中,我在主程序中将数组转换为 void *

int pop_array(void *array, int index, int size, int type) {
    if (index >= size) return 0;
    unsigned char *dst = (unsigned char*) array + index + type;
    memmove(dst, dst + type, type * (size - index - 1));
    return 1;
}

int main(int argc, const char * argv[]) {
    int a[5] = {1, 2, 3, 4, 5};
    pop_array((void *)a, 2, 5);
    for (int i = 0; i < 4; i++) {
        printf("%d\n", a[i]);
    }

    float b[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
    pop_array((void *)a, 2, 5);
    for (int i = 0; i < 4; i++) {
        printf("%f\n", a[i]);
    }
}

正如预期的那样,这会产生

1
2
4
5

1.1
2.2
4.4
5.5

这让我只能创建和维护一个功能。然而,这看起来如此简单,以至于我很惊讶它不是一种更广泛使用的技术,或者至少我在我的小经验中意识到这一点。编写这个函数或将数组转换为我没有看到的 void * 是否有一些后果,或者这是在 C 中使函数类型不可知的合法方法?

你这样做的方式很好。但是你确实有一个错误:

unsigned char *dst = (unsigned char*) array + index + type;

您的提升幅度不合适。这应该是:

unsigned char *dst = (unsigned char*) array + (index * type);

此外,调用函数时不需要转换为 void *

pop_array(a, 2, 5, sizeof(int));

此技术用在 qsort 函数中,该函数可以对任意类型的数组进行排序。它的签名如下:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

与您的函数一样,它需要一个 void * 到数组的开头以及元素的数量和每个元素的大小。它还采用一个函数指针,其工作是执行特定于类型的比较。