关于函数式编程:是否可以在C函数内构建函数?

Is it possible to build functions within a function in C?

对于类赋值,我们编写一个接受输入的程序,并使用qsort对每行输入进行排序,并使用strcmp作为其比较器函数。 因为strcmp的类型与qsort所需的类型不同,所以需要构建包装函数以满足qsort。

我对此并不满意,并希望编写一个函数,它接受类型的函数:

1
int (*cmp)(const char *, const char *)

并返回类型的函数:

1
int (*qsortcmp)(const void *, const void *)

这可能吗? 我写过太多haskell了吗? 我想知道。


C不支持lambda函数。 您唯一的选择是创建一个qsort所需类型的函数,并从该函数内部调用strcmp

例如:

1
2
3
4
5
6
int qsort_cmp_str(const void *a, const void *b)
{
    const char *s1 = a;
    const char *s2 = b;
    return strcmp(s1, s2);
}


只有一个全局变量才能保存真正的函数来调用它。 (是的,那太可怕了。)

有一个原因:只有明显参数的函数指针不能代表闭包。 如果qsort接受了类型的指针

1
int (*)(void *closure, const void*, const void*)

并且void*为每次比较传递它,可以写一个转换器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
struct char_qsorter {
  int (*function)(void*, const char*, const char*);
  void *param;
};
struct qsorter {
  int (*function)(void*, const void*, const void*);
  void *param;
};

int char_qsort_wrapper(void *closure, const void *a, const void *b) {
  const char_qsorter *const cq=closure;
  return cq->function(cq->param, a, b);
}
qsorter convert(const char_qsorter *cq) {
  const qsorter ret={char_qsort_wrapper, cq};
  return ret;
}

/* Convert a plain function pointer: */
int trivial_wrapper(void *closure, const char *a, const char *b) {
  return (*(int (*const *)(const char*, const char*))closure)(a, b);
}
char_qsorter trivial_closure(int (*const *f)(const char*, const char*)) {
  const char_qsorter ret={trivial_wrapper, f};
  return ret;
}

void sort_strings(const char *const *ss, size_t n) {
  int (*const f0)(const char*, const char*)=strcmp;
  const char_qsorter cq=trivial_closure(&f0);
  const qsorter q=convert(&cq);
  qsort_closure(ss, n, sizeof(*ss), q.function, q.param);
  /* or just pass q if the library used the struct */
}

我认为很明显为什么在实践中人们更喜欢硬编码的解决方案。 (实际上,懒惰的程序员只是直接传递strcmp,这适用于大多数实现。)

C11确实支持qsort_s,但它是一个特殊的可选函数,添加了奇怪的运行时错误检查。