【问题标题】:Flexibility of functions in CC中函数的灵活性
【发布时间】:2022-01-10 12:06:35
【问题描述】:

假设我在 C 中有一个函数,它接受两个 void 指针作为输入,*a 和 *b 说,以及一个本身接受两个 void 指针的函数(作为指针)。例如,函数可能有一个类似

的声明
arbitrary_type f(void *a, void *b,
                   arbitrary_type (*g)(void *, void *)) 
{
      ...
}

我们还假设该函数仅通过函数 'g' 起作用(可以将其视为一种 getter 或 setter,用于 'a' 和 b' 所指向的变量。)

从技术上讲,该函数是否能够对type_a *atype_b *brtype (\*g)(type_a *, type_b *) 形式的指针的任意三元组(a, b, g) 进行操作而不会引入错误?

【问题讨论】:

  • 你刚刚重新发明了qsort()。所以是的,它有效。
  • 关于“该函数在技术上是否能够作用于任意三元组”:不,不完全是。传递指向限定类型​​的指针,例如const charvolatile unsigned,会引入一些问题。

标签: c function-pointers void-pointers


【解决方案1】:

该函数在技术上是否能够作用于type_a *atype_b *brtype (\*g)(type_a *, type_b *) 形式的指针的任意三元组(a, b, g)

是的。

不引入错误?

哦。嗯...这一切都归结为g 指向的任何东西的实现。不幸的是,一旦您将void * 用于任何事情,您就已经将任何类型安全的概念抛到了窗外并进入迎面而来的交通。

这几乎就是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_intcompare_dbl 函数负责将参数转换为适当的类型以进行比较。但问题是——没有什么能阻止你这样做:

int arr[100];
...
qsort( arr, 100, sizeof arr[0], compare_dbl );

没有任何一种编译时或运行时检查来确保您已经为您尝试排序的数组类型传递了正确的比较函数。由于qsort 和您的比较函数都使用void * 来表示所有内容,因此编译器无法知道您为正在使用的数组类型传递了错误的比较函数。

是的,您可以对任意类型的组合进行操作。不,您不能保证这样做不会引入任何错误。

【讨论】:

    【解决方案2】:

    该函数在技术上是否能够作用于 type_a *a、type_b *b、rtype (*g)(type_a *, type_b *) 形式的指针的任意三元组 (a, b, g)

    是的。

    不引入错误?

    嗯,这取决于实际的代码。请注意,void * 指针删除了编译器静态检查指针类型是否正确的能力。


    这很大程度上取决于您要建模的接口,但您可以使用一个void * 指针,让用户将两个a b 变量与一个结构“绑定”在一起。

    【讨论】:

    • 这个答案说“取决于实际代码”;在我看来这太模糊了。最好提供正确和错误代码的示例。 this answer 中的一些提示是针对类似问题的,但也不好,因为该问题被标记为 C/C++。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多