如何使 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 *
到数组的开头以及元素的数量和每个元素的大小。它还采用一个函数指针,其工作是执行特定于类型的比较。
我一直在用 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 *
到数组的开头以及元素的数量和每个元素的大小。它还采用一个函数指针,其工作是执行特定于类型的比较。