C 中函数的灵活性
Flexibility of functions in C
假设我在 C 中有一个函数接受两个 void 指针作为输入,比如 *a 和 *b,还有一个函数(作为指针)本身接受两个 void 指针。例如,该函数可能有一个像
这样的声明
arbitrary_type f(void *a, void *b,
arbitrary_type (*g)(void *, void *))
{
...
}
我们还假设该函数仅通过函数 'g' 起作用(对于 'a' 和 b'.)
该函数在技术上是否能够作用于 type_a *a
、type_b *b
、rtype (\*g)(type_a *, type_b *)
形式的指针的任意三元组 (a, b, g)
而不会引入错误?
Would that function technically be capable of acting on arbitrary triples (a, b, g) of pointers of the form type_a *a, type_b *b, rtype (*g)(type_a *, type_b *)
是的。
without introducing errors?
嗯,这取决于实际代码。请注意,void *
指针删除了编译器静态检查指针类型是否正确的能力。
这在很大程度上取决于您正在建模的接口,但是您可以采用一个 void *
指针,让用户将两个 a
b
变量与一个结构“绑定”在一起。
Would that function technically be capable of acting on arbitrary triples (a, b, g)
of pointers of the form type_a *a
, type_b *b
, rtype (\*g)(type_a *, type_b *)
是的。
without introducing errors?
哦。嗯...这一切都归结为 g
指向的任何内容的实现。不幸的是,一旦你将 void *
用于任何事情,你就已经将任何类型安全的概念从 window 中扔到了迎面而来的交通中。
这几乎就是 qsort
标准库函数的工作原理 - 您将指向数组的指针(作为 void *
)、元素数量、每个元素的大小传递给它,和一个指向比较两个元素的函数的指针:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
如果要对 int
的数组进行升序排序,可以这样写一个比较函数:
int compare_int( const void *l, const void *r )
{
const int *a = l;
const int *b = r;
if ( *a < *b )
return -1;
else if ( *a > *b )
return 1;
return 0;
}
int main( void )
{
int arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_int );
}
我们可以对 double
:
的数组做同样的事情
int compare_dbl( const void *l, const void *r )
{
const double *a = l;
const double *b = r;
if ( *a < *b )
return -1;
else if ( *a > *b )
return 1;
return 0;
}
int main( void )
{
double arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_dbl );
}
compare_int
和compare_dbl
函数负责将参数转换为合适的类型进行比较。但这就是问题 - 没有什么能阻止你这样做:
int arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_dbl );
没有任何类型的编译时或 运行 时检查来确保您已经为您尝试排序的数组类型传递了正确的比较函数。由于 qsort
和您的比较函数对所有内容都使用 void *
,因此编译器无法知道您为正在使用的数组类型传递了错误的比较函数。
是的,您可以对任意类型的组合进行操作。不,您不能保证这样做不会引入任何错误。
假设我在 C 中有一个函数接受两个 void 指针作为输入,比如 *a 和 *b,还有一个函数(作为指针)本身接受两个 void 指针。例如,该函数可能有一个像
这样的声明arbitrary_type f(void *a, void *b,
arbitrary_type (*g)(void *, void *))
{
...
}
我们还假设该函数仅通过函数 'g' 起作用(对于 'a' 和 b'.)
该函数在技术上是否能够作用于 type_a *a
、type_b *b
、rtype (\*g)(type_a *, type_b *)
形式的指针的任意三元组 (a, b, g)
而不会引入错误?
Would that function technically be capable of acting on arbitrary triples (a, b, g) of pointers of the form type_a *a, type_b *b, rtype (*g)(type_a *, type_b *)
是的。
without introducing errors?
嗯,这取决于实际代码。请注意,void *
指针删除了编译器静态检查指针类型是否正确的能力。
这在很大程度上取决于您正在建模的接口,但是您可以采用一个 void *
指针,让用户将两个 a
b
变量与一个结构“绑定”在一起。
Would that function technically be capable of acting on arbitrary triples
(a, b, g)
of pointers of the formtype_a *a
,type_b *b
,rtype (\*g)(type_a *, type_b *)
是的。
without introducing errors?
哦。嗯...这一切都归结为 g
指向的任何内容的实现。不幸的是,一旦你将 void *
用于任何事情,你就已经将任何类型安全的概念从 window 中扔到了迎面而来的交通中。
这几乎就是 qsort
标准库函数的工作原理 - 您将指向数组的指针(作为 void *
)、元素数量、每个元素的大小传递给它,和一个指向比较两个元素的函数的指针:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
如果要对 int
的数组进行升序排序,可以这样写一个比较函数:
int compare_int( const void *l, const void *r )
{
const int *a = l;
const int *b = r;
if ( *a < *b )
return -1;
else if ( *a > *b )
return 1;
return 0;
}
int main( void )
{
int arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_int );
}
我们可以对 double
:
int compare_dbl( const void *l, const void *r )
{
const double *a = l;
const double *b = r;
if ( *a < *b )
return -1;
else if ( *a > *b )
return 1;
return 0;
}
int main( void )
{
double arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_dbl );
}
compare_int
和compare_dbl
函数负责将参数转换为合适的类型进行比较。但这就是问题 - 没有什么能阻止你这样做:
int arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_dbl );
没有任何类型的编译时或 运行 时检查来确保您已经为您尝试排序的数组类型传递了正确的比较函数。由于 qsort
和您的比较函数对所有内容都使用 void *
,因此编译器无法知道您为正在使用的数组类型传递了错误的比较函数。
是的,您可以对任意类型的组合进行操作。不,您不能保证这样做不会引入任何错误。