W skrócie: Tak można uzyskać dostęp za pomocą metod statycznych wskaźników.
Aby to zrozumieć, lepiej jest zrozumieć nieco więcej tego, co dzieje się pod maską kompilatora.
Dla przejrzystości, skompilowany program jest zapisany w kodzie maszynowym. W skompilowanym programie znajdują się dodatkowe informacje dotyczące "programu ładującego program", ale sam program to instrukcje, które musi wykonać procesor.
Po wywołaniu funkcji "foo()" w C, kompilator języka C przetłumaczy to na operację procesora "CALL". Operacja CALL jest wykonywana w kodzie przez adres foo (dosłownie adres pamięci lub "offset"). Zauważ, że ponieważ jest to adres pamięci, nazwa ("foo") nie jest używana. Zauważ też, że linker nie musi wiedzieć o "foo", aby to działało.
Gdy wywołujesz funkcję "bar()" w C, a funkcja znajduje się w innej jednostce kompilacji (innym pliku C), kompilator ma mały problem, ponieważ nie wie, gdzie w programie (gdzie in pamięć) funkcją jest wywoływanie. To znaczy, że nie wie, jaki adres wpisać po operacji CALL. Gdy tak się stanie, zapisuje kod pozostawiając miejsce na adres, ale pozostawia notatkę dla linkera. Nota mówi linkerowi "wpisz tutaj adres paska". Łącznik koryguje napisany program za pomocą adresu pamięci. Aby umożliwić linkerowi to zrobić; kompilator zapisuje tabelę zawierającą każdą nazwę funkcji i odpowiedni adres w kodzie.
Co robi statyczny? To po prostu mówi kompilatorowi, aby nie zapisywał nazwy i adresu dla funkcji w tabeli przekazywanej do łącznika. Funkcja nadal istnieje w kodzie jako funkcja, ale linker nie wie, gdzie on jest. Każdy kod w tej samej jednostce kompilacji będzie wiedział, gdzie jest ta funkcja. Każda funkcja w tej samej jednostce kompilacji może przekazać adres funkcji jako wskaźnik poza jednostką kompilacji.
kod C użyć, aby przekazać wskaźnik funkcji jest coś takiego:
file1.h
typedef void (* VoidFunctionPointer)();
extern VoidFunctionPointer somethingInteresting;
bar();
file1.c
#include "a.h"
VoidFunctionPointer somethingInteresting;
static void foo() {
// do something interesting;
}
void bar() {
// we know what foo is because we're in the same compilation unit
somethingInteresting = foo;
}
file2.c
#include "a.h"
int main(int argC, char ** argV) {
bar();
// we can call somethingInteresting as if it is a function no matter
// wether it's declared static in code or not
// this can be foo, just as long as we don't have to use the name "foo"
somethingInteresting();
}
W tym pliku kodu2 w efekcie uruchamia funkcję statyczną z pliku1. Klucz jest taki, że plik2 nigdy nie potrzebuje nazwy tej funkcji, więc statyczny nie ma wpływu na wskaźniki funkcji.
mogę polecić przeczytaniu opisu Microsoft formatu PE (EXE i DLL) [tutaj]:
http://msdn.microsoft.com/en-us/library/ms809762.aspx
Jeśli chcesz uzyskać dostęp do funkcji z innych jednostek kompilacji, dlaczego robisz to "statyczne" w pierwszej kolejności? – Jon
@Jon: można zadeklarować wywołanie zwrotne jako statyczne (nikt nie może wywołać funkcji po jego identyfikatorze) i wysłać jego wskaźnik do funkcji konfiguracji, aby zareagować na zdarzenie. Zmuszasz go do funkcji wywołania zwrotnego, a nie do wywoływania jako zwykły. – Gauthier
@Gauthier: W takim przypadku nie musisz robić nic więcej niż po prostu przekazać adres adresatowi: 'takes_callback (foo)' - Widzę, że już to zasugerowałeś. OP pyta (tak jak ja i inni, którzy odpowiedzieli, że to widzimy) na globalnie dostępny wskaźnik funkcji, który jest całkowicie bezcelowy. Oczywiście to nie przeszkadza ludziom w odpowiadaniu na dosłowne pytanie dotyczące moar rep * * ... –
Jon