【问题标题】:Functions inside functions in C [duplicate]C中函数内部的函数[重复]
【发布时间】:2009-06-05 19:10:26
【问题描述】:

我正在制作一个类似这样的代码:

#include <stdio.h>

double some_function( double x, double y)
{
  double inner_function(double x)
  { 
    // some code
    return x*x;
  }

  double z;
  z = inner_function(x);
  return z+y;

}

int main(void)
{
  printf("%f\n", some_function(2.0, 4.0));
  return 0;
}

这在 GCC 中完美编译(没有警告),但在 ICC 中编译失败。

ICC 给出:

main.c(16): error: expected a ";"
    { 
    ^

main.c(21): warning #12: parsing restarts here after previous syntax error
    double z;
            ^

main.c(22): error: identifier "z" is undefined
    z = inner_function(x);
    ^

compilation aborted for main.c (code 2)

我做错了什么?

谢谢。

(编辑)对不起这个可怜的例子。在我的原始代码中,我有点需要做这些事情。我正在使用 GSL 数值积分器并有类似的东西:

double stuff(double a, double b)
{
  struct parameters
  {
    double a, b;
  };

  double f(double x, void * params)
  {
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
  }
  struct parameters par = {a,b};

  integrate(&f, &par);

}

我有很多具有这种结构的函数:它们是函数与大量外部参数集成的结果。而实现数值积分的函数必须接收一个指向函数类型的指针:

double f(double x, void * par)

我真的很希望以这种方式嵌套函数,这样我的代码就不会因大量函数而膨胀。我希望我可以用 ICC 编译它以加快速度。

【问题讨论】:

  • 你们太棒了!!在不到 2 分钟的时间里,我得到了完整的答案!!
  • 你好,我喜欢你喜欢的函数......
  • 这就是为什么我需要 C 中的 lambda 表达式。:(
  • 关于“我根本不明白为什么你真的需要嵌套函数。”,更多人转向这种开发风格的原因是转向 JavaScript 的命名空间和范围机制。一个函数封装了其他函数,并通过一个结构体暴露了函数。这是否会简化开发或未来库的使用,我还没有看到。

标签: c function


【解决方案1】:

嵌套函数以language extension in GCC 的形式提供,但它们不是标准语言的一部分,因此某些编译器不允许使用它们。

【讨论】:

  • +1 - OP 的快速说明:我认为您在 GCC 中遇到了错误,即使它支持嵌套函数,因为您拼错了函数名称。 inner_funcion() 应该是 inner_function()。
  • 我明白了。感谢您的快速回答。我在使用它时没有注意到它不是标准的。这很糟糕。我发现如果我坚持使用 icc,我的代码将很难理解。
  • 上次从 JavaScript 迁移到 C 时,我尝试使用嵌套函数。我喜欢嵌套函数。但不要放弃让 C 语言易于阅读、理解和调试。这是可行的。
【解决方案2】:

其他人都给了你一个规范的答案“标准 C 中不允许嵌套函数”(所以它们的任何使用取决于你的编译器)。

您修改后的示例是:

double stuff(double a, double b)
{
  struct parameters
  {
    double a, b;
  };

  double f(double x, void * params)
  {
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
  }
  struct parameters par = {a,b};

  return integrate(&f, &par);     // return added!
}

既然你说积分器等功能需要

  double (*f)(double x, void * par);

我完全不明白为什么你真的需要嵌套函数。我希望写:

struct parameters
{
    double a, b;
};

static double f(double x, void *params)
{
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
}

double stuff(double a, double b)
{
    struct parameters par = { a, b };
    return integrate(f, &par);
}

上面的代码应该可以在 C89 或 C99 中运行(除非像这样初始化 'par' 存在问题);此版本的代码仅适用于 C99,使用复合文字作为参数(第 6.5.2.5 节复合文字):

double stuff(double a, double b)
{
    return integrate(f, &(struct parameters){a, b});
}

很有可能您对“结构参数”类型只有几个变体。您确实需要为各种函数提供单独(足够)有意义的名称 - 每个源文件只能有一个名为“f”的函数。

嵌套函数版本的唯一边际、微小的好处是您可以确定除了stuff 之外没有其他函数调用f。但是鉴于示例代码,这并不是一个主要的好处; f 的静态定义意味着这个文件之外的任何函数都不能调用它,除非传递一个指向函数的指针。

【讨论】:

  • 嗨乔纳森,我使用嵌套函数的理由是,因为 f 除了计算积分之外在任何地方都不是用户,我认为这是使代码对自己更具可读性的好方法。但也许不是。我有很多函数需要积分(它实际上是一个耦合方程组的解,其中每个方程都是一个积分)我认为只在代码中浮动一次的函数是不好的做法。如果我可以像在 python 或 Haskell 中那样使用 lambda 函数,那就太好了。但我需要速度来解决这个问题,并且对 Haskell 了解不够。
【解决方案3】:

C 没有嵌套函数。 GCC 的嵌套函数是该语言的扩展。

您在 GCC 中的运行时错误是拼写错误。 inner_funcion 应该是 inner_function

【讨论】:

  • 哦。哎呀。谢谢,我更正了函数的名称。
  • 他们到底为什么要在 C 中添加这样一个非标准的扩展?是否有编译器开关可以将其关闭?
  • 不确定。大概。我记得当我开始 iPhone 开发时,我曾选择在 XCode 中启用它们。我决定不启用。我喜欢嵌套函数,但对我来说,直接 C 的一大优势是可移植性。
  • 查看我的答案,了解如何编写 ISO C90 可移植代码。
  • @Nick Presta -- 感谢您的提示。
【解决方案4】:

正如上面许多答案所提到的,C 不支持内部函数,但是可以在 C++ 中使用内部来完成类似的事情。不幸的是,它们使用起来有点笨拙,但如果您不介意编译为 C++,它可能是您的选择。

未经测试的示例:

double some_function( double x, double y)
{
  struct InnerFuncs
  {
    double inner_function(double x)
    { 
      // some code
      return x*x;
    }
    // put more functions here if you wish...
  } inner;

  double z;
  z = inner.inner_function(x);
  return z+y; 
}

请注意,此答案不应暗示我认为内部函数在您展示的用法中是一个好主意。

多年后编辑:

C++ 现在允许我们使用 lambdas 作为内部函数。在我上面的玩具示例中,它看起来很像这样:

double some_function( double x, double y)
{
   auto inner_function = [&]() { return x * x; }

   double z;
   z = inner_function ();
   return z + y;
}

请注意,局部变量 x 会在 lambda 内部自动捕获,这是一个非常好的功能。

更多:What is a lambda expression in C++11?

【讨论】:

  • 如果我使用这个 C++ 代码而不是我原来的 C 代码,效率损失会很重要吗?
  • 我怀疑效率是否会明显下降。
  • 这很酷!这几乎就像我又拥有了 javascript 的内部函数一样!
【解决方案5】:

您正在使用嵌套函数 - C 不支持这样的东西。

【讨论】:

    【解决方案6】:

    这不是有效的 C 代码,C 不支持内部函数

    【讨论】:

      【解决方案7】:

      函数内部的局部函数定义在 C 中是非法的。

      【讨论】:

        【解决方案8】:

        嵌套函数不是 C 标准的一部分。因此,不能保证它适用于所有编译器,绝对应该避免使用。

        【讨论】:

          【解决方案9】:

          如果您想知道如何关闭 GCC 扩展等。

          您可以使用-ansi 标志,它将标准设置为 c89,并关闭与 ISO C90 不兼容的 GCC 功能。

          请参阅docs 了解更多信息。也请查看-std 标志。

          【讨论】:

            【解决方案10】:

            我不是专家,但我敢打赌这是 C99 规范明确不允许或未定义的,因此最好远离它。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-04-11
              • 2011-11-11
              • 1970-01-01
              • 2014-12-21
              • 2016-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多