Компилятор GNU C содержит хорошее расширение для языка C, которое называется Вложенные функции а>. Тем не менее, документация неясна в некоторых моментах. Например, говорится, что
Можно вызвать вложенную функцию из-за пределов области ее имени, сохранив ее адрес или передав адрес другой функции [...]
Если вы попытаетесь вызвать вложенную функцию через ее адрес после выхода из содержащей функции, все пойдет наперекосяк.
Если вы попытаетесь вызвать его после выхода из уровня области видимости, и если он ссылается на некоторые переменные, которые больше не находятся в области видимости, вам может повезти, но рисковать неразумно.
Однако если вложенная функция не ссылается ни на что, выходящее за рамки, вы должны быть в безопасности.
Итак, с одной стороны, там говорится, что если вы вызываете вложенную функцию после выхода из содержащей ее функции, все рушится, но в нескольких предложениях впереди говорится, что есть обстоятельства, при которых это можно сделать.
Я предполагаю, что под вещами, выходящими за рамки, подразумеваются автоматические переменные, поэтому, в частности, рефакторинг должен быть безопасным.
static int f() { ... }
int outer() {
... // some use of f
}
в
int outer() {
int f() { ... } // f does not refer to outer's local variables
... // some use of f
}
если в модуле нет других применений f
, кроме как в функции outer
, даже если предположить, что функция outer
каким-то образом пропускает адрес f
за пределы своей области.
Однако я был удивлен, обнаружив, что следующий код не компилируется
int main(void) {
void nested_function(void) {}
static const struct { void (*function_pointer)(void); } s = {
.function_pointer = nested_function
};
return 0;
}
с жалобой на то, что initializer element is not constant
(т.е. nested_function
).
Есть ли причина для этого ограничения? (Я не могу представить, чтобы адрес функции был непостоянным, даже если он вложен)