Gcc Nested Functions(巢狀函數定義)

2020-08-14 19:09:36

GCC巢狀函數定義

參考文獻: https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Nested-Functions.html

巢狀函數是定義在另一個函數內部的函數。巢狀函數在GNU C中被支援作爲擴充套件,但是GNU c++不支援, 巢狀函數的名稱對於定義它的塊來說是區域性的。

例如: 我們的函數傳入一個參數並計算這個參數的四次方返回,我們可以用x * x * x * x * x表示,也可以使用pow函數,但是這個例子僅僅是爲了說明巢狀函數的使用。

在这里插入图片描述

巢狀函數可以存取所有在它的定義塊中的變數,比如,我們將原本的quadratic定義爲:

int quadratic() {
    return number * number;
}

源程式就成了這樣:

#include <stdio.h>

int fourthPower(int number) {
  int quadratic() {
    return number * number;
  }
  return quadratic(number) * quadratic(number);
}

int main() {
  printf("10 ^ 4 = %d\n", fourthPower(10));
  return 0;
}

編譯執行結果和上面相同,就不展示了。
結論: 在允許變數定義的地方,函數內都允許巢狀函數定義。巢狀函數可以使用所定義處的區域性變數

我們繼續往下看:

It is possible to call the nested function from outside the scope of its name by storing its address or passing the address to another function

通過儲存巢狀函數的地址或將地址傳遞給另一個函數,可以從其名稱的作用域之外呼叫巢狀函數:

int nestedFunctionPower(int number) {
  int quadratic() {
    return number * number;
  }
  int(*qua)() = quadratic;

  return (*qua)(number);
}

GCC使用一種稱爲trampolines的技術來實現獲取巢狀函數的地址。這種技術在c++的詞法閉包中有描述(Thomas M. Breuel, USENIX C++ Conference Proceedings, October 17-21, 1988).

文獻中還有一句話:

A nested function can jump to a label inherited from a containing function, provided the label is explicitly declared in the containing function (see Local Labels). Such a jump returns instantly to the containing function, exiting the nested function that did the goto and any intermediate functions as well

總的來說就是在巢狀函數裏面可以使用goto 蹦噠到外面,因爲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;
}

如果您需要在巢狀函數的定義之前宣告它,請使用auto(否則對於函數宣告來說,這是毫無意義的)。