C 如何生成返回函数的函数?
大图:我有一个带函数的模块,还有一个在这些函数上带有过程和函数的模块 当我组合两个函数时(从函数的模块接口): 在几个方面,(其中一个是添加): 以下(部分)实现没有问题:C 如何生成返回函数的函数?,c,function,pointers,modularity,C,Function,Pointers,Modularity,大图:我有一个带函数的模块,还有一个在这些函数上带有过程和函数的模块 当我组合两个函数时(从函数的模块接口): 在几个方面,(其中一个是添加): 以下(部分)实现没有问题: z1 = (*f)(param1, x); z2 = (*g)(param2, x); y = z1 + z2; return y; 但当我想返回指向“新”函数的指针时,类似于: void *OP_PAdd( double (*f)(double,double), double param3 ); 我不能让它正常工作,也
z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;
但当我想返回指向“新”函数的指针时,类似于:
void *OP_PAdd( double (*f)(double,double), double param3 );
我不能让它正常工作,也不能打正确的“电话”。我想在其他函数中使用输出“函数”作为输入。当从另一个函数返回函数时,最干净的方法是使用
typedef
:
typedef double (*ftype)(double, double);
然后您可以这样声明您的函数:
ftype OP_PAdd( ftype f, double param3 )
{
....
return f1;
}
typedef double ftype(double, double);
您可以在不使用typedef
的情况下执行此操作,但它很混乱:
double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
return f1;
}
因此,当您将函数指针用作其他函数的参数或返回值时,请使用typedef
编辑:
虽然您可以这样声明类型:
ftype OP_PAdd( ftype f, double param3 )
{
....
return f1;
}
typedef double ftype(double, double);
在实践中,您永远不能直接使用这样的类型。函数不能返回函数(只返回函数的指针),并且不能将此类型的变量赋值给
此外,您不需要显式地取消引用函数指针来调用函数,因此指针本身是隐藏的这一事实并不是什么大问题。将函数指针定义为typedef
也是惯例。从:
#包括
类型定义无效(*sighandler_t)(内部);
信号机(内部信号机、信号机);
你的意思是这样的吗?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;
}
编辑:在@dbush-answer下的注释之后,此版本将从typedef
作为指针返回到函数。它给出了相同的输出,但在decider()
中,无论我是否编写返回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;
}
#包括
#包括
typedef-double(乐趣)(double,double);
双加(双a,双b){
返回a+b;
}
双接头(双a、双b){
返回a-b;
}
双mul(双a、双b){
返回a*b;
}
乐趣*决策者(字符操作){
开关(op){
案例“+”:return add;//return&add;
案例'-':返回子节点;
案例“*”:返回mul;
}
出口(1);
}
内部主(空)
{
fun*foo;
foo=决策者('+');
printf(“%f\n”,foo(42.0,24.0));
foo=决策者('-');
printf(“%f\n”,foo(42.0,24.0));
foo=决策者('*');
printf(“%f\n”,foo(42.0,24.0));
返回0;
}
在C中,您可以返回指向函数的指针,但要做到这一点,函数首先需要存在,而且动态创建函数不是C所说的可能,更不用说如何实现了
如果您的代码只在一个操作系统和一个处理器上工作(可能还有一些其他限制),您可以:
分配内存页
编写数据和机器代码,执行所需操作,调用指针传递的函数等
将内存保护从读/写更改为读/执行
返回指向已创建函数的指针
不要担心每个函数需要4kB
可能有这样的库,但不一定是可移植的其他答案是正确和有趣的,但您应该知道,在可移植C99中,不可能有真正的as C函数(这是C的一个基本限制)。如果您不知道闭包是什么,请仔细阅读关于闭包的wiki页面(并阅读,尤其是其)。但是请注意,在中,确实有闭包,使用和。大多数其他编程语言(Ocaml、Haskell、Javascript、Lisp、Clojure、Python等)都有闭包
由于C中缺少真正的闭包(“数学上”C函数中唯一的闭包值是全局变量或静态变量或文本),大多数接受C函数指针的库都提供了一个API来处理一些客户端数据(可以是一个简单的例子,但更认真地看一下内部)。客户端数据(通常是一个不透明的指针)可用于保持闭合值。您可能希望遵循类似的约定(因此系统地将函数指针作为回调传递给其他客户机数据),因此您需要更改C函数的签名(而不是只传递原始函数指针,而是将函数指针和一些客户机数据作为回调传递给“模拟”闭包)
有时,您可以在运行时生成一个C函数(使用非标准特性,可能需要操作系统或某些外部库的帮助)。您可以使用一些库,例如,(两者都将快速生成一些运行缓慢的代码),(您将显式生成每个机器指令,并且您有责任发出快速x86-64代码),或者(两者都在现有编译器之上,因此可以用来发出一些优化的代码,速度稍微慢一点)。在POSIX和Linux系统上,您还可以在一些临时文件/tmp/tempcode.C
中发出一些C代码,将该代码的编译(例如gcc-fPIC-Wall-O2-shared/tmp/tempcode.C-o/tmp/tempcode.so
)放入插件中,并使用&
我们不知道你所编码的实际应用程序是什么,但是你可以考虑在其中嵌入一些解释器,例如。然后,您将使用并向嵌入式计算器/解释器提供回调。我在这里会非常恼火,所以请保持冷静
标准的C api附带了两个函数,分别称为setjmp
和longjmp
。撇开糟糕的命名不谈,它们基本上是将当前状态的副本(包括堆栈位置和寄存器值)存储到jmp_buf
(或者,技术名称是continuation
)中
66.000000
18.000000
1008.000000
#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;
}
jmp_buf jb;
void sfunc(void) {
void *sp_minus1 = 0xBEEFBABE;
setjmp(jb);
}
#include <inttypes.h> // intptr_t
#include <setjmp.h> // longjmp, setjmp
#include <stdio.h> // printf
#include <stdlib.h> // malloc, free
#include <string.h> // memcpy
typedef struct {
jmp_buf jb;
int fixupc;
int fixupv[10];
size_t stack_size; // this is only an approximation
void *stack_ptr;
} CLOSURE;
int getclosure(CLOSURE *closure) {
unsigned int i, size;
void *i_ptr = &i, *sp;
unsigned char *data = (unsigned char *)(void *)closure->jb;
memset(closure, 0, sizeof(CLOSURE));
if (!setjmp(closure->jb)) {
printf("looking for 0x%08X...\n\n", (unsigned int)(intptr_t)i_ptr);
for (i = 0; i < sizeof(closure->jb); i++) {
memcpy(&sp, &data[i], sizeof(void *));
size = (unsigned int)(intptr_t)(sp - i_ptr);
if (size < 0x300) {
closure->fixupv[closure->fixupc++] = i;
printf(" fixup @ 0x%08X\n", (unsigned int)(intptr_t)sp);
if (sp > closure->stack_ptr) {
closure->stack_size = size;
closure->stack_ptr = sp;
}
}
}
if (!closure->stack_ptr)
return 0;
printf("\nsp @ 0x%08X\n", (unsigned int)(intptr_t)closure->stack_ptr);
printf("# of fixups = %i\n", closure->fixupc);
/*
* once we allocate the new stack on the heap, we'll need to fixup
* any additional stack references and memcpy the current stack.
*
* for the sake of this example, I'm only fixing up the pointer
* to the stack itself.
*
* after that, we would have successfully created a closure...
*/
closure->stack_size = 1024;
sp = malloc(closure->stack_size);
memcpy(sp, closure->stack_ptr, closure->stack_size);
memcpy(&data[closure->fixupv[0]], &sp, sizeof(void *));
closure->stack_ptr = sp;
return 1;
} else {
/*
* to this bit of code right here
*/
printf("holy shit!\n");
return 0;
};
}
void newfunc(CLOSURE *closure) {
longjmp(closure->jb, 1);
}
void superfunc(CLOSURE *closure) {
newfunc(closure);
}
int main(int argc, char *argv[]) {
CLOSURE c;
if (getclosure(&c)) {
printf("\nsuccess!\n");
superfunc(&c);
free(c.stack_ptr);
return 0;
}
return 0;
}
double retfunc()
{
return 0.5;
}
double (*fucnt)()
{
return retfunc;
}
main()
{
printf("%f\n", (*funct())());
}
jmp_buf jb;
void *myfunc(void) {
static struct {
// put all of your local variables here.
void *new_data, *data;
int i;
} *_;
_ = malloc(sizeof(*_));
_.data = _;
if (!(_.new_data = (void *)(intptr_t)setjmp(jb)))
return _.data;
_.data = _.new_data;
/* put your code here */
free(_);
return NULL;
}
void *data = myfunc();
longjmp(jb, (int)(intptr_t)data);