W języku C nie ma wsparcia dla funkcji zagnieżdżonych na poziomie standardu ANSI/ISO. Historycznie C został zaprojektowany jako kompaktowy język, bliski sprzętu, gdzie funkcja istniała na najwyższym poziomie jednostki translacji (pliku). W przeciwieństwie do języków takich jak Pascal, C nie pozwala na zadeklarowanie funkcji wewnątrz innej funkcji czysto syntaktycznie.
Problem, z którym borykają się programiści: często chcą używać lokalnych funkcji pomocniczych, widocznych tylko wewnątrz jednej funkcji, aby zainkapować logikę lub uniknąć duplikacji kodu. Wbudowane wsparcie dla zagnieżdżenia umożliwiłoby ograniczenie zasięgu widoczności i uczyniłoby kod bardziej modułowym.
Jednym z popularnych sposobów rozwiązania tego problemu jest użycie funkcji statycznych (static) na poziomie pliku, przekazywanie wskaźników do funkcji zewnętrznych, lub naśladowanie zagnieżdżenia za pomocą struktur z funkcjami callback. W razie potrzeby "zamykania" kontekstu można stosować struktury ze wskaźnikami na dane (analogiczne do closure).
Przykład naśladowania "lokalnej" funkcji poprzez przekazanie wskaźnika:
#include <stdio.h> static int helper(int x) { return x * x; } void myFunction(void) { printf("Kwadrat liczby 5: %d\n", helper(5)); }
Kluczowe cechy:
Czy można zdefiniować funkcję wewnętrzną wewnątrz innej funkcji w standardowym C i ją wywołać?
Nie. W języku C (standard ANSI/ISO) nie można zadeklarować funkcji wewnątrz innej funkcji. Próba tego spowoduje błąd kompilacji. Niektóre niestandardowe rozszerzenia (np. w GCC) to umożliwiają, ale takie programy nie będą przenośne.
Czy funkcje statyczne mogą całkowicie zastąpić zagnieżdżone pod względem sensu i bezpieczeństwa?
Funkcje statyczne ograniczają zasięg widoczności do funkcji-pliku, ale nie do funkcji-bloku. Oznacza to, że funkcje statyczne są dostępne z dowolnego kodu w tym samym pliku, co nie gwarantuje pełnej inkapsulacji jak w przypadku prawdziwych funkcji zagnieżdżonych.
Czy można wdrożyć "zamykania" (closures) w funkcjach zagnieżdżonych w czystym C?
Nie, bezpośrednio nie ma takiego wsparcia. Można jednak użyć struktur, które zawierają wskaźnik na dane i funkcję, co przybliży zachowanie do closure:
typedef struct { int context; int (*func)(int, int); } closure; int add(int a, int b) { return a + b; } closure cl = { .context = 5, .func = add };
Programista używa rozszerzenia GCC - deklaruje funkcje wewnętrzne w projekcie, po czym kod nie kompiluje się w MSVC i innych kompilatorach.
Zalety:
Wady:
Programista dla wszystkich funkcji pomocniczych ogranicza zasięg widoczności do static, stosuje strukturę do przekazywania kontekstu.
Zalety:
Wady: