MCL*_*MCL 40 c pointers modularity function
大图:我有一个带有功能的模块和一个带有这些功能的程序和功能的模块.
当我组合两个函数时(来自函数的模块接口):
double f1(double alpha, double x);
double f2(double beta, double x);
Run Code Online (Sandbox Code Playgroud)
在几个方面,(其中一个是添加):
double OP_Addition(double (*f)(double,double) , double (*g)(double,double), double param1, double param2, double x);
Run Code Online (Sandbox Code Playgroud)
以下(部分)实现没有问题:
z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;
Run Code Online (Sandbox Code Playgroud)
但是当我想返回指向"新"函数的指针时,类似于:
void *OP_PAdd( double (*f)(double,double), double param3 );
Run Code Online (Sandbox Code Playgroud)
我无法让它正常工作,也没有做出正确的"通话".我想在其他函数中使用输出"function"作为输入.
dbu*_*ush 32
从另一个函数返回函数时,最简单的方法是使用typedef:
typedef double (*ftype)(double, double);
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样声明你的函数:
ftype OP_PAdd( ftype f, double param3 )
{
....
return f1;
}
Run Code Online (Sandbox Code Playgroud)
你可以在没有a的情况下做到这一点typedef,但它很麻烦:
double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
return f1;
}
Run Code Online (Sandbox Code Playgroud)
因此,当您将函数指针作为参数或返回其他函数的值时,请使用a typedef.
编辑:
虽然你可以声明这样的类型:
typedef double ftype(double, double);
Run Code Online (Sandbox Code Playgroud)
在实践中,你永远不能直接使用这样的类型.函数不能返回函数(仅指向函数的指针),并且不能将此类型的变量赋值给.
此外,您不需要显式取消引用函数指针来调用函数,因此指针本身被隐藏的事实不是一个大问题.将函数指针定义为a也是惯例typedef.从手册页signal:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Run Code Online (Sandbox Code Playgroud)
Bas*_*tch 25
其他答案是正确和有趣的,但你应该知道在便携式C99中,没有办法将真正的闭包作为C函数(这是C的一个基本限制).如果你不知道什么是封,读了仔细对他们的wiki页面(也读SICP,尤其是其§1.3).但请注意,在C++ 11中,您使用std :: function和lambda-expressions进行闭包.大多数其他编程语言(Ocaml,Haskell,Javascript,Lisp,Clojure,Python,......)都有闭包.
由于C中缺少真正的闭包("数学上"C函数中唯一的闭合值是全局或静态变量或文字),大多数接受C函数指针的库都提供了一些带有一些客户端数据的API处理回调(一个简单的例子可能是qsort_r,但更严肃地看看GTK内部).客户端数据(通常是不透明指针)可用于保持闭合值.您可能希望遵循类似的约定(因此系统地将函数指针作为带有一些额外客户端数据的回调传递),因此您需要更改C函数的签名(而不是只传递原始函数指针,您将通过函数指针和一些客户端数据作为回调,以"模拟"闭包.
有时您可以在运行时生成C函数(使用非标准功能,可能在操作系统或某些外部库的帮助下).您可以使用一些JIT编译库,例如GNU lightning,libjit(两者都会快速生成一些运行缓慢的代码),asmjit(您将明确生成每个机器指令,并且您有责任发出快速的x86-64代码),GCCJIT或LLVM(两者都在现有的编译器之上,所以可以用来缓慢地发出一些优化的代码).在POSIX和Linux系统上,您还可以在一些临时文件中发出一些C代码,将该代码/tmp/tempcode.c的编译(例如gcc -fPIC -Wall -O2 -shared /tmp/tempcode.c -o /tmp/tempcode.so)分成一个插件,并使用dlopen(3)和dlsym(3)动态加载生成的插件.
顺便说一下,我们不知道您编写的实际应用程序是什么,但您可以考虑在其中嵌入一些解释器,例如Lua或Guile.然后,您将使用并向嵌入式评估程序/解释程序提供回调.
Wea*_*ane 13
你的意思是这样的吗?该decider()函数返回指向另一个函数的指针,然后调用该函数.
#include <stdio.h>
#include <stdlib.h>
typedef double(*fun)(double, double);
double add(double a, double b) {
return a + b;
}
double sub(double a, double b) {
return a - b;
}
double mul(double a, double b) {
return a * b;
}
fun decider(char op) {
switch(op) {
case '+': return add;
case '-': return sub;
case '*': return mul;
}
exit(1);
}
int main(void)
{
fun foo;
foo = decider('+');
printf("%f\n", foo(42.0, 24.0));
foo = decider('-');
printf("%f\n", foo(42.0, 24.0));
foo = decider('*');
printf("%f\n", foo(42.0, 24.0));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
节目输出:
66.000000
18.000000
1008.000000
Run Code Online (Sandbox Code Playgroud)
编辑:在@dbush答案下的评论之后,这个版本从typedef作为指针退回到一个函数.它提供相同的输出,但在decider()它中编译干净并提供正确的输出,无论我是否写return add;或return &add;
#include <stdio.h>
#include <stdlib.h>
typedef double(fun)(double, double);
double add(double a, double b) {
return a + b;
}
double sub(double a, double b) {
return a - b;
}
double mul(double a, double b) {
return a * b;
}
fun *decider(char op) {
switch(op) {
case '+': return add; // return &add;
case '-': return sub;
case '*': return mul;
}
exit(1);
}
int main(void)
{
fun *foo;
foo = decider('+');
printf("%f\n", foo(42.0, 24.0));
foo = decider('-');
printf("%f\n", foo(42.0, 24.0));
foo = decider('*');
printf("%f\n", foo(42.0, 24.0));
return 0;
}
Run Code Online (Sandbox Code Playgroud)