2012-01-17 8 views
6

Dokładniej, dlaczego w wielu przypadkach jest to ta sama nazwa z wieloma różnymi nazwami i dlaczego typy wskaźnika (czasem zaciemniające logikę) są różne?Dlaczego wszystko w Windows API zostało wpisane?

Na przykład:

typedef const WCHAR *LPCWSTR, *PCWSTR;

Jaki jest sens tego?

+4

Nie znam wszystkich szczegółów, ale myślę w 16-bitowych dniach w systemie Windows 3.1. Wówczas były dwa różne typy wskaźników, bliskie i dalekie wskaźniki. Zdefiniowali typy wskaźników dla każdego (odpowiednio "PCWSTR" i "LPCWSTR") dla jednolitego interfejsu. Ze względu na kompatybilność wsteczną, do której dążyła firma Microsoft, z tego powodu pozostaliśmy obaj z tych typów w interfejsie API. –

+1

Prawdziwe pytanie brzmi: dlaczego usunięto inne typy wskaźników, które nie mają za daleko historii dalekiego wskaźnika? Takich jak HANDLE, HWND, HINSTANCE itp. O ile mi wiadomo, nie ma racjonalnej odpowiedzi na to pytanie. – Lundin

+2

@Lundin: HANDLE, HWND i tak nie są w rzeczywistości wskaźnikami: są one nieprzezroczystymi uchwytami, które są prywatne dla niektórych części systemu Windows (USER, GDI, KERNEL). Za kulisami mogą być one faktycznie używane jako wskaźniki w wewnętrznych tabelach lub podobnych. Są one typowane jako puste * specjalnie po to, aby było jasne, że powinny być przekazywane tylko tak jak są, a kod nie powinien próbować ich interpretować (np. Poprzez robienie arytmetyki na nich - co byłoby łatwe do zrobienia przez przypadek, gdyby były wartościami int); inny cel niż to, co dzieje się z typedefs w powyższym qu. – BrendanMcK

Odpowiedz

7

Powodem istnienia zarówno PCWSTR, jak i LPCWSTR jest to, że w czasach starożytnych istniała różnica. LPCWSTR był kiedyś const WCHAR FAR *.

4

Uważam, że jednym z głównych celów tego projektu jest umożliwienie tego, by typy funkcji służyły jako dokumentacja ich przeznaczenia i oczekiwanych formatów danych.

+0

Jaka jest różnica między 'LP' i' P' w 'typedef's dla typów wskaźników? Chodzi mi o to, że widzimy przykład, w którym są "wpisani" w to samo ... –

+5

Mogę się mylić, ale myślę, że jest to historyczny artefakt z 16-bitowego Windowsa, w którym miałeś oba wskaźniki i "długie wskazówki". Były wtedy oddzielnymi typami, ale teraz potrzebny jest tylko jeden typ. Oba są obsługiwane ze względu na kompatybilność wsteczną. –

18

Jest rzeczywiście kilka różnych rzeczy dzieje się tutaj:

  • najpierw daleko/wskaźniki: Powrót Win16 dni, trzeba było bliskie i dalekie wskaźniki; bliskie wskaźniki były w zasadzie tylko 16-bitowymi przesunięciami, więc mogły odnosić się tylko do obiektów w obrębie 64k domyślnego wskaźnika danych aplikacji (DS lub Segment danych), ale były małe i szybkie; mając na uwadze, że większy "długi wskaźnik" lub długi wskaźnik składał się zarówno z segmentu, jak i przesunięcia, więc mógł odnosić się do wszystkiego w przestrzeni adresowej 1M. Kiedy pojawił się 386, cały ten segment: firma offsetowa ostatecznie odeszła, a wszystkie wskaźniki były tylko 32-bitowymi adresami w płaskie 32-bitowe przestrzenie adresowe. I dlatego są wersje P ... i LP ...

  • Po co zawracać sobie głowy typingefs? To po prostu wygoda lub skrót: wpisanie "LPSTR" jest wygodniejsze niż "const char far *". Ale staje się również rozpoznawalnym idiomem: widzisz LPSTR i od razu wiesz, że tak właśnie Windows radzi sobie z ciągami w swoim API.

  • Jest tu również abstrakcja: Windows zazwyczaj definiuje własne wersje typów i używa ich zamiast wersji C. Więc interfejsy API Windows używają DWORD zamiast int, lub VOID zamiast void. Było to potrzebne do podłączania niektórych otworów w C w tym czasie - nie było żadnego boola, więc wprowadzenie BOOL uniknęło, aby różne API używały różnych typów do reprezentowania wartości boolowskich (np. Char vs int). W pewnym stopniu spowodowało to, że interfejs API systemu Windows był niezależny od podstawowej implementacji C: C nie wymaga, aby int miało określony rozmiar: może to być 16 bitów lub 32 bity w zależności od kompilatora. Ale dla interfejsu API systemu operacyjnego ważne jest dokładne określenie tych rzeczy. Zamiast więc używać int lub long, Windows zamiast tego używa INT i LONG, które następnie definiuje jako potrzebne, i wpisuje w typie C, który wykonuje rzeczywistą pracę.

  • Wreszcie, niektóre z tych typów wskazują na konkretne zastosowania poza informacjami o typie. BOOL i INT są typowane jako int, ale jasne jest, że parametr API określony jako BOOL będzie używany w znaczeniu TRUE/FALSE, a nie jako wartość całkowita. (Pamiętaj, że to poprzedza typ "bool".) Podobnie, BYTE - który jest znakiem unsigned - sugeruje, że parametr będzie faktycznie używany jako ośmiobitowa wartość liczbowa, a nie jako znak alfanumeryczny lub symbol. LPSTR wskazuje, że wartość ma być zakończonym znakiem NUL łańcuchem, a nie tylko wskazywać na dowolne wartości char. BSTR i LPWSTR mają ten sam podstawowy typedef - oba są WCHAR * - ale BSTRy mają prefiks długości i muszą być przydzielone za pomocą API SysAllocString, mając osobny typedef tutaj pomaga utrzymać dwa oddzielne w kodzie i dokument API wymagania: jeśli widzisz interfejs API, który przyjmuje parametr BSTR jako parametr, wtedy wiesz, że nie możesz po prostu przekazać szerokiego ciągu znaków, nawet jeśli podstawowy typ jest taki sam, istnieją dodatkowe wymagania dla tego parametru.

Powiązane problemy