Spec-Zone.ru › GCC 11

Далее: Нелокальные переходы, Предыдущее: Метки как значения, Вверх: Расширения семейства языков C [Оглавление][Индекс]

6.4 Вложенные функции ¶

Вложенная функция — это функция, определённая внутри другой функции. Вложенные функции поддерживаются как расширение в GNU C, но не поддерживаются в GNU C++.

Имя вложенной функции локально для блока, где оно определено. Например, здесь мы определяем вложенную функцию по имени square, и вызываем её дважды:

foo (double a, double b)
{
  double square (double z) { return z * z; }

  return square (a) + square (b);
}

Вложенная функция может обращаться ко всем переменным содержащей функции, которые видны в момент её определения. Это называется лексическим охватом. Например, здесь мы показываем вложенную функцию, которая использует унаследованную переменную по имени offset:

bar (int *array, int offset, int size)
{
  int access (int *array, int index)
    { return array[index + offset]; }
  int i;
  /* … */
  for (i = 0; i < size; i++)
    /* … */ access (array, i) /* … */
}

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

Возможен вызов вложенной функции извне области видимости её имени путём хранения её адреса или передачи адреса другой функции:

hack (int *array, int size)
{
  void store (int index, int value)
    { array[index] = value; }

  intermediate (store, size);
}

Здесь функция intermediate получает адрес store в качестве аргумента. Если intermediate вызывает store, аргументы, переданные store, используются для хранения в array. Но этот метод работает только до тех пор, пока содержащая функция (hack, в данном примере) не завершит работу.

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

GCC реализует получение адреса вложенной функции, используя метод, называемый трамплинами. Этот метод был описан в «Лексические замыкания для C++» (Томас М. Брюэль, Труды конференции USENIX по C++, 17-21 октября 1988 г.).

Вложенная функция может перейти к метке, унаследованной от содержащей функции, при условии, что метка явно объявлена в содержащей функции (см. Локально объявленные метки). Такой переход мгновенно возвращает в содержащую функцию, выходя из вложенной функции, которая выполнила goto и всех промежуточных функций. Вот пример:

bar (int *array, int offset, int size)
{
  __label__ failure;
  int access (int *array, int index)
    {
      if (index > size)
        goto failure;
      return array[index + offset];
    }
  int i;
  /* … */
  for (i = 0; i < size; i++)
    /* … */ access (array, i) /* … */
  /* … */
  return 0;

 /* Control comes here from access
    if it detects an error.  */
 failure:
  return -1;
}

Вложенная функция всегда не имеет связи. Объявление её с extern или static является ошибкой. Если вам нужно объявить вложенную функцию до её определения, используйте auto (что в противном случае не имеет смысла для объявлений функций).

bar (int *array, int offset, int size)
{
  __label__ failure;
  auto int access (int *, int);
  /* … */
  int access (int *array, int index)
    {
      if (index > size)
        goto failure;
      return array[index + offset];
    }
  /* … */
}

Далее: Нелокальные переходы, Предыдущее: Метки как значения, Вверх: Расширения семейства языков C [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/gcc/Nested-Functions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API