C语言中的函数指针及其行为

C语言中的函数指针及其行为,c,gcc,segmentation-fault,C,Gcc,Segmentation Fault,我在试验c和函数指针。下面的代码可以很好地使用gcc作为编译器 typedef int( * one_var_func)(int); int Multiply(int x, int y) { return x * y; } one_var_func curry(int( * f)(int, int), int x) { int curried_f(int y) { return f(x, y); } return (curried_f); } int apply(i

我在试验c和函数指针。下面的代码可以很好地使用gcc作为编译器

typedef int( * one_var_func)(int);

int Multiply(int x, int y) {
  return x * y;
}

one_var_func curry(int( * f)(int, int), int x) {
  int curried_f(int y) {
    return f(x, y);
  }
  return (curried_f);
}

int apply(int( * f)(int), int x) {
  return f(x);
}

int main() {
  int( * p)(int, int);
  one_var_func q;
  int e;
  p = & Multiply;
  q = curry(p, 2);
  e = apply( * q, 10);
  printf("%d \n", e);
  return 1;
}
但是当我做这个小修改的时候,

int apply(int (*f)(int) ,int x){
  int a;
  a=f(x)
  return a;
}

程序抛出一个分段错误。我不明白为什么和怎么做。解释一下就好了。

嵌套函数是一个gcc扩展。gcc文档指出,一旦包含函数调用退出,任何指向嵌套函数的指针都将无效,至少如果它们尝试任何高级变量引用


这是有意义的,因为只要包含函数处于活动状态,它的局部变量就保持分配状态,并且可以解析嵌套函数的上层引用。但是一旦包含函数退出,它就需要支持闭包来保留堆栈框架,而实际上它不支持闭包。

嵌套函数是一个gcc扩展。gcc文档指出,一旦包含函数调用退出,任何指向嵌套函数的指针都将无效,至少如果它们尝试任何高级变量引用


这是有意义的,因为只要包含函数处于活动状态,它的局部变量就保持分配状态,并且可以解析嵌套函数的上层引用。但是,一旦包含函数退出,它就需要支持闭包来保留堆栈框架,而它没有。嵌套函数是标准C中不存在的GCC扩展,因此这个答案(如问题)是特定于GCC的

C中的嵌套函数不提供闭包。也就是说,在外部函数返回之前,嵌套函数只能访问外部函数的局部变量。在这个问题上,政府有以下几点要说:

如果您试图在包含函数退出后通过其地址调用嵌套函数,那么所有的麻烦都会发生。如果您试图在包含作用域级别退出后调用它,并且如果它引用了一些不再在作用域中的变量,那么您可能很幸运,但冒险是不明智的。但是,如果嵌套函数未引用超出范围的任何内容,则应该是安全的

两个版本的代码都违反了这个规则,那么为什么只有一个版本会导致segfault呢?一个答案是,就像“未定义的行为”一样,“万劫不复”可以描述所有类型的行为,包括看似按预期工作的行为


更面向实现的答案是,从函数返回实际上并不会立即擦除堆栈上的内容-值只是停留在那里,直到另一个函数在需要堆栈空间时重写它们。引入新的局部变量会使函数需要更多的堆栈空间,因此第二个函数会覆盖以前版本没有的堆栈内存。

嵌套函数是标准C中不存在的GCC扩展,因此此答案(如问题)是特定于GCC的

C中的嵌套函数不提供闭包。也就是说,在外部函数返回之前,嵌套函数只能访问外部函数的局部变量。在这个问题上,政府有以下几点要说:

如果您试图在包含函数退出后通过其地址调用嵌套函数,那么所有的麻烦都会发生。如果您试图在包含作用域级别退出后调用它,并且如果它引用了一些不再在作用域中的变量,那么您可能很幸运,但冒险是不明智的。但是,如果嵌套函数未引用超出范围的任何内容,则应该是安全的

两个版本的代码都违反了这个规则,那么为什么只有一个版本会导致segfault呢?一个答案是,就像“未定义的行为”一样,“万劫不复”可以描述所有类型的行为,包括看似按预期工作的行为


更面向实现的答案是,从函数返回实际上并不会立即擦除堆栈上的内容-值只是停留在那里,直到另一个函数在需要堆栈空间时重写它们。引入一个新的局部变量会使函数需要更多的堆栈空间,因此第二个函数会覆盖以前版本没有的堆栈内存。

C没有闭包的概念,因此不可能基于普通函数指针实现curry。您在这里尝试的是使用闭包:

这意味着嵌套函数“捕获”了
x
的值。但是在C中,一旦执行离开封闭范围,任何具有自动存储持续时间的变量就不再存在,并且没有闭包概念可以防止这种情况发生

考虑到C中甚至不存在嵌套函数,尽管GCC支持将其作为扩展,但如果确实需要应用curry,则必须定义自己的“函数对象”。标准C中的示例如下所示:

#include <stdio.h>
#include <stdlib.h>

typedef struct intfunc
{
    int (*f)();
    void *ctx;
} intfunc;

typedef struct curryctx
{
    int (*f)();
    int x;
} curryctx;

static int currycall(void *ctx, int x)
{
    curryctx *cctx = ctx;
    return cctx->f(cctx->x, x);
}

int intfunc_call(intfunc f, int x)
{
    return f.ctx ? f.f(f.ctx, x) : f.f(x);
}

intfunc createfunc(int (*f)())
{
    return (intfunc){f, 0};
}

intfunc curryfunc(int (*f)(), int x)
{
    curryctx *cctx = malloc(sizeof *cctx);
    if (!cctx) exit(1);
    cctx->f = f;
    cctx->x = x;
    return (intfunc){currycall, cctx};
}

static int multiply(int x, int y)
{
    return x*y;
}

int main()
{
    intfunc multiply_by_two = curryfunc(multiply, 2);
    printf("%d\n", intfunc_call(multiply_by_two, 10));
    free(multiply_by_two.ctx);
    return 0;
}
#包括
#包括
typedef结构intfunc
{
int(*f)();
无效*ctx;
}intfunc;
类型定义结构curryctx
{
int(*f)();
int x;
}CurryCx;
静态int currycall(无效*ctx,int x)
{
curryctx*cctx=ctx;
返回cctx->f(cctx->x,x);
}
intfunc_调用(intfunc f,intx)
{
返回f.ctx?f.f(f.ctx,x):f.f(x);
}
intfunc createfunc(int(*f)()
{
返回(intfunc){f,0};
}
intfunc curryfunc(int(*f)(),intx)
{
curryctx*cctx=malloc(sizeof*cctx);
如果(!cctx)退出(1);
cctx->f=f;
cctx->x=x;
返回(intfunc){currycall,cctx};
}
静态整数乘法(整数x,整数y)
{
返回x*y;
}
int main()
{
intfunc乘以2=curryfunc(乘以2);
printf(“%d\n”,intfunc_调用(乘以二,10));
自由(乘以2.ctx);
返回0;
}

当然,这会很快变得复杂,所以我建议您最好完全忘记这个想法。

C没有闭包的概念,因此不可能基于普通函数指针实现curry。你在这里尝试的是
#include <stdio.h>
#include <stdlib.h>

typedef struct intfunc
{
    int (*f)();
    void *ctx;
} intfunc;

typedef struct curryctx
{
    int (*f)();
    int x;
} curryctx;

static int currycall(void *ctx, int x)
{
    curryctx *cctx = ctx;
    return cctx->f(cctx->x, x);
}

int intfunc_call(intfunc f, int x)
{
    return f.ctx ? f.f(f.ctx, x) : f.f(x);
}

intfunc createfunc(int (*f)())
{
    return (intfunc){f, 0};
}

intfunc curryfunc(int (*f)(), int x)
{
    curryctx *cctx = malloc(sizeof *cctx);
    if (!cctx) exit(1);
    cctx->f = f;
    cctx->x = x;
    return (intfunc){currycall, cctx};
}

static int multiply(int x, int y)
{
    return x*y;
}

int main()
{
    intfunc multiply_by_two = curryfunc(multiply, 2);
    printf("%d\n", intfunc_call(multiply_by_two, 10));
    free(multiply_by_two.ctx);
    return 0;
}
one_var_func curry(int( * f)(int, int), int x) 
{
  int curried_f(int y) 
  {
    return f(x, y);  //f and x are local to curry 
  }
  return (curried_f);
}
int curried_f(int y) 
{
    return f(x, y);  //f and x are local to curry 
}
function-definition:
  declaration-specifiers declarator  declaration-listopt compound-statement
q = curry(p, 2);
e = apply( * q, 10);