Функции внутри функций в C

Я делаю код, похожий на этот:

#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, чтобы немного ускорить работу.

Ответ 1

Все остальные предоставили вам канонический ответ: "Вложенные функции не разрешены в стандартном 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 (если нет проблемы с инициализацией "par" ) или C99; эта версия кода предназначена только для C99, используя составной литерал для параметра (раздел 6.5.2.5 Компонентные литералы):

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

Шансы превосходны, что у вас есть только несколько вариантов типа "структурных параметров". Вам нужно предоставить отдельные (достаточно) значащие имена для различных функций - у вас может быть только одна функция, называемая "f" для исходного файла.

Единственное предельное крошечное преимущество версии вложенной функции заключается в том, что вы можете быть уверены, что никакая другая функция, кроме stuff, вызывает f. Но, учитывая примерный код, это не главное преимущество; статическое определение f означает, что никакая функция вне этого файла не может вызвать его, если не передана указатель на функцию.

Ответ 2

Вложенные функции доступны в качестве расширения языка в GCC, но они не являются частью стандартного языка, поэтому некоторые компиляторы не позволят им.

Ответ 3

C не имеет вложенных функций. Вложенные функции GCC являются расширением языка.

Ошибка выполнения в GCC является орфографической ошибкой. inner_funcion должен быть inner_function.

Ответ 4

Как уже упоминалось выше, внутренние функции не поддерживаются в 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; 
}

Обратите внимание, что этот ответ не должен подразумевать, что я считаю, что внутренние функции являются хорошей идеей в использовании, которое вы показали.

Год спустя:

С++ теперь позволяет использовать lambdas в качестве внутренних функций. В случае моего примера с игрушкой выше это выглядело бы так:

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

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

Обратите внимание, что локальная переменная x автоматически фиксируется внутри лямбда, что является очень приятной функцией.

Подробнее здесь: Что такое лямбда-выражение в С++ 11?

Ответ 5

Вы используете вложенные функции - C не поддерживает такие вещи.

Ответ 6

Это не действительный код C, внутренние функции не поддерживаются в C

Ответ 7

локальные определения функций внутри функции являются незаконными в C.

Ответ 8

Вложенные функции не являются частью стандартов C. Поэтому нет никакой гарантии, что он будет работать для всех компиляторов и определенно следует избегать.

Ответ 9

В случае, если вам интересно, как отключить расширения GCC и т.д.

Вы можете использовать флаг -ansi, который по существу устанавливает стандарт на c89 и отключает функции GCC, которые несовместимы с ISO C90.

Для получения дополнительной информации см. docs. Проверьте флаг -std.

Ответ 10

Я не эксперт, но я готов поспорить, что это либо явно не разрешено, либо undefined по спецификации C99, поэтому лучше всего держаться подальше от него.