2010-06-04 15 views
6

Po prostu staram się lepiej zrozumieć zewnętrzne funkcje C.lepsze zrozumienie zewnętrznych funkcji "C"

Zgodnie z moją wiedzą, zewnętrzna funkcja C jest zawsze funkcją, do której próbujesz wywołać z aplikacji, która została już skompilowana. Biblioteka wykonywalna, statyczna lub dynamiczna.

extern "C" 
{ 
    HRESULT CreateDevice(); 
    typedef HRESULT (*CREATEDEVICE)(); 

    HRESULT ReleaseDevice(); 
    typedef HRESULT (*RELEASEDEVICE)(); 
} 

Więc moje pytanie brzmi ...

Czy moje rozumienie poprawne ??

Czy zawsze musi to być wskaźnik funkcji C?

Dlaczego musisz używać typedef dla każdej funkcji?

Zakładam, że podczas korzystania z GetProcAddress(). Przydzielasz pamięć na te konkretne aplikacje HEAP, a nie na tę, z której ją wywołujesz. Dlatego musisz zwolnić go również z tej sterty?

+0

Czy widzisz to pytanie? http://stackoverflow.com/questions/67894/why-do-we-we-need-extern-c-include-foo-h-in-c – Jujjuru

Odpowiedz

1

Nie musi to być wskaźnik funkcji. Możesz określić deklarację funkcji normalnie i poprzedzić ją extern "C", jak pokazano w some Microsoft examples.

Jeśli używasz GetProcAddress(), nie przydzielasz żadnej pamięci. Otrzymasz po prostu adres pamięci funkcji wewnątrz biblioteki DLL, która została już załadowana do pamięci (prawdopodobnie z LoadLibrary()).

nawet przy użyciu wskaźników funkcji (takich jak te zwracane przez GetProcAddress) nie mają używać typedef, to tylko, że kod wygląda całkiem brzydki bez niego. Zawsze ciężko jest się dowiedzieć, co napisać. Myślę, że byłoby to coś takiego:

void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice"); 
+0

Pamiętaj, że __cdecl jest specyficzne dla Microsoft. –

+2

@Billy ONeal: Tak samo jest z 'GetProcAddress' i Visual Studio. – dreamlax

+0

GetProcAddress nie jest specyficzne dla Microsoft, ale jest specyficzne dla systemu Windows. Mogę użyć GetProcAddress z MinGW na przykład, ale nie __cdecl. –

0

extern "C" {} jest C++ konwencja o stwierdzenie, że załączone funkcje C funkcje - nie funkcje C++. C++ ma nieco inną konwencję nazewnictwa, która jest w konflikcie z C. Jeśli masz bibliotekę napisaną w C i chcesz użyć jej w programie C++, musisz użyć zewnętrznego "C" {}, aby kompilator wiedział, że są to funkcje C. Jeśli biblioteka została napisana w C++, wierzę, że zewnętrzna "C" {} spowoduje błąd.

Należy zauważyć, że extern ma wiele znaczeń - ten konkretny przypadek jest konwencją C++ i nie ma związku z różnymi zastosowaniami extern. Na przykład:

extern int count; 

ma zupełnie inne znaczenie niż zewnętrzne "C" {}.

Typedef jest oddzielny od zewnętrznego wydania "C" {}. typedefs pozwala tworzyć aliasy dla typowych typów, które mają więcej sensu. Na przykład deklarowanie struktur jest często pełnym procesem. Mogę używać typedef, aby go skrócić:

struct mystruct {int a; int b}; 
typedef struct mystruct returncode; 
// I can now declare a variable as type 'returncode' 
returncode a; 

Zatem w przykładzie HRESULT jest naprawdę aliasem (* CREATEDEVICE)(), chociaż wierzę, trzeba umieścić go przed funkcją (a nie po) .

4

zewnętrzne "C" ma 2 implikacje. Po pierwsze, deklaruje, że symboliczne nazwy funkcji nie są "zmanipulowanymi nazwami" w celu obsługi C++. Po drugie, informuje kompilator, że funkcja jest wywoływana przy użyciu konwencji wywoływania C, a nie konwencji wywoływania PASCAL.Różnica polega na tym, kiedy adres powrotu jest pchany na stosie. Używanie niewłaściwej konwencji wywoływania spowoduje awarię aplikacji.

Ta deklaracja dotyczy kompilatora, a nie łącznika. Tak więc zewnętrzna funkcja C mogłaby istnieć w twoich własnych modułach lub w bibliotece binarnej: źródło rzeczywistych bajtów dla implementacji funkcji jest rozwiązywane przez linker. Jeśli podpis funkcji jest zadeklarowany jako zwykła funkcja C++, a nie jako zewnętrzny C, kompilator zapisze nazwę symboliczną, aby zakodować informacje o typie z podpisu funkcji. Spowoduje to, że będzie on niezgodny z kodem obiektowym generowanym przez inne kompilatory C++. Dlatego tworzenie zewnętrznej funkcji C umożliwia współdzielenie kodu pomiędzy kompilatorami w postaci binarnej. Zauważ, że nie możesz w ten sposób odsłonić funkcji członków, tylko stare funkcje w stylu C.

0

Jednym z ważnych aspektów określania połączenia extern "C" jest to, że nazwy funkcji nie są zniekształcane, co jest domyślnym ustawieniem dla nazw C++.

Aby funkcji biblioteki, aby mogły być ładowane przy użyciu GetProcAddress, trzeba też dodać funkcję do .def file użyć __declspec(dllexport) lub użyj extern "C".

0

odpowiedzieć, w kolejności:

  • extern funkcje "C" są wykorzystywane do współdziałanie z C z C++. Używanie ich powoduje, że kod C może wywoływać funkcję. Ponieważ API systemu Windows jest API C, wszystkie funkcje są zewnętrzne "C", aby zapewnić, że kod C i C++ może korzystać z interfejsu API.

  • Aby programy C++ współdziałały z innymi językami, w tym C, jako konwencja, funkcje eksportowane są przy użyciu zewnętrznego "C". Dlatego wiele kodu dll to robi. Nie jest to jednak wymóg techniczny.

  • Więc nie, NIE musi to być wskaźnik funkcji C.

  • Nie musisz też używać maszyn typedef.

Podany kod przykładowy pochodzi z pliku nagłówkowego, który dwukrotnie publikuje eksportowanie biblioteki DLL - raz jako zestaw zewnętrznych metod "C", które są eksportowane, aby dll mogła być statycznie połączona. drugi jako zestaw typów wskaźników funkcji, tak aby dll mógł być ładowany dynamicznie, oraz typy wskaźników funkcji używane z GetProcAddress.