【问题标题】:Change signature of function pointer in C when one argument is constant当一个参数为常量时,更改 C 中函数指针的签名
【发布时间】:2017-12-14 15:46:20
【问题描述】:

我想在 C 中使用快速排序,它的函数签名为 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)),但我的比较函数的签名是 int (*compar)(const void *, const void*, const int),第三个参数在一次调用快速排序期间保持不变。

作为说明,假设我想根据不同的范数(例如 L0、L1、L2 和 Linifinity 范数)对向量数组进行排序。它实际上是哪个规范,作为第三个参数传递给比较函数,但在调用qsort 期间保持不变。是否可以像

这样的形式进行分配
//Function declaration for parametric comparison
int cmp3(int* a_vec, int* b_vec, int x);

// Somewhere in main
int (*cmp2)(int, int);
cmp2 = cmp3(int*, int*, 2);//2 could mean L2 norm

能够调用类似的东西

qsort(a, 100, sizeof(a), cmp2);

我知道这行不通,但我希望它能让我知道我想要完成什么。此外,由于不同比较方式的数量太大,无法进行不同的比较函数和调用 qsort。

【问题讨论】:

  • 我也想过一个全局变量,但它很难看(我需要线程安全)
  • @ForceBru 这是一个很好的答案
  • 你可以只拥有多个比较函数并传入需要的一个吗?
  • 您可能正在寻找qsort_r() — 但请注意qsort_r() 的 Linux 和 BSD/macOS 变体不同。

标签: c pointers function-pointers quicksort


【解决方案1】:

这被称为partial function application,你只能用 C 中的包装器来实现这样的事情:

int cmp3(int *a, int *b) {
    return cmp2(a, b, 2);
} 

如果您正在研究偏函数应用程序或者映射或纯函数,您可能需要研究函数式编程语言,例如 Haskell。

【讨论】:

  • “你只能用 C 中的包装器来实现它”,这绝不是一个偏函数应用程序。
  • @Stargateur,是吗?部分应用是将多个参数固定到一个函数的过程,产生另一个较小的函数。所以,这正是cmp3 作为cmp 的包装器所做的事情:我们有cmp2(int*, int*, int) 并最终得到cmp3(int* a, int* b) == cmp2(a, b, 2);
  • 您没有减少函数的元数,而是创建了第二个元数更小的函数:/。 stackoverflow.com/a/5531152/7076153,答案是否定的。 C中的函数不是主要值。不能部分申请。
  • @Stargateur,对,C 本身并不支持(与 Haskell 不同),但无论如何都可以创建类似的东西。是的,部分应用涉及修复一些函数的参数并生成另一个函数,这正是cmp3 所做的。
  • 不,这不是,void (*function)(void *, void *) = cmp2(2); 可能是名称部分应用程序。你没有减少任何东西,你创建了一个全新的功能,g(x, y) -> f(x, y, 2) 不是部分应用。 f(x, y, 2) -> g(x, y) 是。但如果你认为这是部分应用,请写一本书告诉世界。我想人们会喜欢知道在 C 中做部分应用是如此简单。
【解决方案2】:

主要问题是函数签名在调用之前需要堆栈中的 3 个元素。旧的 C 编译器很“聪明”,如果您没有传递足够多的参数,它们就会用空变量(归零)“完成”堆栈。

现在,如果您这样做(假设编译器接受),它将在堆栈中具有未定义值的第三个变量,而不是您期望的值。

您应该像之前的评论所说的那样做一个“代理”功能:

int cmp3(int *a, int *b) {
    return cmp2(a, b, 2);
}

【讨论】:

  • 感谢您对堆栈的澄清,这是我在阅读上述回复后正在考虑的一件事
  • 我不确定您在考虑哪种“智能 C 编译器”,但在过去 30 多年中我还没有遇到过这样的。
  • 我过去使用过 Digital Unix C 编译器,它可以编译: void function(int a, int b, int c); int main(int argc,char**argv){ function(12,13)​​;返回0; } 没有什么问题。它将 0 传递给最后一个变量。而“聪明”是由于其接受此类代码的奇怪行为。
猜你喜欢
  • 2018-12-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多