Development z Zapomnianej Strony

..:: Paweł Hofman .NET Portal ::..

Nieprawdą jest, że na platformie .NET nie istnieją wskaźniki. W C# w sekcji unsafe, możemy spokojnie mieszać "typowy" kod .NET z operacjami na wskaźnikach. Tu jednak uwaga:

  1. sekcje unsafe muszą być propagowane w górę, a to oznacza, że i metoda, w której są zawarte, musi być również opisana jako niebezpieczna (czasem i cała klasa),
  2. oraz co dużo ważniejsze - podczas kompilacji modułu (assembly) wymagany jest przełącznik "/unsafe", zezwalający jawnie na używanie niebezpiecznych operacji na wskaźnikach.

Co ciekawe - dostępny staje się dobrze znany z C/C++ operator sizeof (a nie, jak wspomniano dotychczas tylko: Marshal.SizeOf() przy P/Invoke).

 

public unsafe void MakeTriple(int *pValue)
{
  *pValue=(*pValue)*3;
}

 

UWAGA!

Wskaźniki są niebezpieczne przede wszystkim z racji istnienia śmieciarza w .NET (zwanego przez niektórych również Garbage Collectorem, w skrócie GC). Otóż ów GC analizuje użycie wszystkich obiektów utworzonych w czasie życia programu .NET-owego i decyduje, które z nich mają być usunięte z pamięci. Nie wdając się zbytnio w szczegóły procesu decyzyjnego, należy zauważyć, iż obiekt, na który wskazywał wskaźnik, może bez żadnego powiadomienia oraz jawnej przyczyny zostać usuniętym, a jego miejsce zupełnie nieużywane. GC może, co gorsze, rozpocząć również proces upakowywania obiektów (usunąć fragmentację pamięci), aby zrobić więcej dla nowych obiektów, a tym samym wskażnik nie będzie już pokazywal poprawnej lokalizacji, bądź wskazywał inny obiekt.

Typowe referencje (do klas lub struktur) nadążają za tą polityką i nie są powodem tego typu błedów. Aby więc zabezpieczyć się, przed owymi niepożądanymi skutkami, używane jest przypinanie obiektów, które nie pozwala GC na żadne manipulacje wskazanym obiektem. Służy do tego słowo kluczowe fixed.

 

public unsafe static void Main()
{
  MyData data = new MyData();
 
fixed ( int *ptr = &data.valueField )
{
   *ptr = *ptr + 10;
}
}



TytanNET jest moim autorskim dodatkiem (add-in) do Visual Studio 2005 oraz 2008. Głównym celem, jaki mi przyświecał przy jego tworzeniu, było ułatwienie pracy i zmniejszenie nudnego kodowania poprzez automatyzację najczęściej wykonywanych akcji. Zalicza się do nich elementy rozszerzające standardowe środowisko IDE o:

 

Ostatnią wersję możesz pobrać tutaj.



Niestety czasami okazuje się, że platforma .NET nie dostarcza funkcjonalności, które łatwo osiągało się, korzystając po prostu z natywnego Win32 API w C/C++. Przykładem tutaj są chociażby zaawansowane operacje na kontrolkach systemowych, haki w systemie (SetWindowsHookEx), zarządzanie systemowymi ustawieniami (głośność, wyciszenie). Albo wręcz przeciwnie - jesteśmy już w posiadaniu gotowego i działającego komponentu, któremu jedyne, co można zarzucić to fakt, iż został napisany właśnie w C/C++.

Rozwiązania są dwa (proponowane i wspierane przez Microsoft):

  1. Zacząć naukę programowania w Managed C++, który będzie stanowił pomost i korzystał z metod i klas w C++, a wystawiał interfejs dla .NET-owych modułów (assemblies),
  2. skorzystać z mechanizmu Platform Invoke (w skrócie P/Invoke).

 

Za *NIE* używaniem opcji (1) przemawia sama złożoność i komplikacje wprowadzane przez ten mieszany język programowania. Ponadto dochodzi również fakt, iż użyta w nim technika IJW (It-Just-Works) nie działa na urządzeniach mobilnych (np. na żadnym PDA z zainstalowanym Windows Mobile 2003 lub nowszym). Większość kodu odpowiedzialnego za przenoszenie danych (zwykłe kopiowanie z jednego typu struktur na drugi) spada na barki programisty. I zapewne jeszcze dużo, dużo więcej...

 

P/Invoke z kolei gwarantuje bardzo proste przekazywanie całych struktur C# do C/C++ (i w drugą stronę) z użyciem zaimportowanych funkcji (słowo kluczowe extern). Począwszy od .NET 2.0 (oraz CompactFramework 2.0) wszystko to osiągną się programując w C#, eliminując potrzebę posiadania dodatkowego projektu (modułu) pośredniczącego.

Dane są automatycznie kopiowane, bazując na kilku zdefiniowanych odgórnie przez Microsoft:

 

Wokól techniki tej zgromadzona jest też społeczność, która większość, jeśli nie wszystkie wywołania systemowe, zebrała i udostępnia pod adresem: pinvoke.net.



Sposób wywoływania funkcji w programach pisanych w C/C++, Pascalu, assemblerze (rozumianych szeroko jako języki i kod niezarządzany) odgrywa niebagatelne znaczenie. Aby dwie funkcje - wywołująca i wywoływana - mogły się ze sobą dogadać, muszą wcześniej uzgodnić kilka drobnych acz istotnych szczegółów. Należą do nich:

  • sposób, w jaki przekazywane będą argumenty (np. poprzez stos, rejestry lub mieszając oba)
  • sposób, w jaki argumenty są numerowane (od prawej, czy od lewej strony)
  • sposób udekorowania nazwy funkcji (poprzez dodanie przyrostków, przedrostków lub całkowite wygenerowanie nowej nazwy, gwarantujące unikatowość, gdy funkcja jest wielkorotnie przeładowana)
  • czy występuje stała, czy zmienna liczba argumentów (a tym samym, która ze stron będzie odpowiedzialna za posprzątanie)
  • czy występuje wywołanie funkcji globalnej (statycznej) lub metody klasy (C++).

Mimo iż kombinacji wymienionych czynników jest sporo, stosuje się głównie 3 konwencje: fastcall, stdcall, thiscall, cdecl.
Poniżej krótkie omówienie, ze wskazaniem najważniejszych cech oraz zastosowania.

 

Konwencja stdcall (__stdcall)

  • argumenty odkładane na stosie od prawej do lewej (od końca)
  • funkcja wywoływana odpowiedzialna jest za usunięcie argumentów ze stosu (jako, że ich rozmiar jest znany)
  • nazwa funkcji zostaje udekorowana  - otrzymuje znak podkreślenia jako przedrostek  a na końcu po znaku małpy, rozmiar argumentów w bajtach (np. void fun(int arg) -> _fun@4)
  • konwencja ta nadaje się wszędzie tam, gdzie występuje znana liczba argumentów oraz występują restrykcje co do rozmiaru kodu binarnego (który mniejszy jest, gdyż to funkcja wywoływana sprząta stos)

 

Konwencja cdecl (__cdecl)

  • argumenty odkładane na stosie również od prawej do lewej (od końca)
  • funkcja wywołująca odpowiedzialna jest za usunięcie argumentów ze stosu (bo zna ich rozmiar), a to pozwala na stosowanie zmiennej liczby argumetów (np.: printf)
  • nazwa funkcji zostaje poprzedzona podkreślnikiem (np. void fun(int arg) -> _fun)
  • generuje dłuższy kod binarny od stdcall (jako, że sprzątanie stosu jest wstawiane po każdym wywołaniu), ale pozwala na wywołania funkcji ze zmienną listą argumentów

Ciekawe porównanie znaleźć można na codeguru.com.

 

Konwencja fastcall (__fastcall)

  • główną zaletą jest fakt, iż argumenty przekazywane są nie przez stos, a rejestry
  • niemniej jednak wymaga to pewnych założeń
    • rejestry te muszą być w chwili wywołania nieużywane (inaczej ich stan będzie odłożony na stos i zyski z takiego przekazywania argumentów zmaleją)
    • używane są tylko niektóre rejestry (i jeśli funcja ma za dużo argumentów lub ich rozmiar jest za dużo, to i tak będą przekazywane przez stos)
    • kolejność użycia rejestrów zależy wyłącznie od użytego kompilatora (i niektóre pozwalają na własne zdefiniowanie tej kolejności)
    • np. Microsoft C++ Compiler używa ECX i EDX, w których umieszcza dwa pierwsze argumenty (bez upakowania jeśli nie są 32-bitowe), a pozostałe odkłada na stos w kolejności od prawej do lewej (od końca)
  • nazwa funkcji jest poprzedzona znakiem małpy i tak samo jak przy stdcall, na końcu dodany jest również znak małpy oraz rozmiar argumentów w bajtach (np. void fun(int a) -> @fun@4).

 

Konwencja thiscall

  • jest to konwencja stosowana najczęściej przy wywołaniu funkcji danej klasy (w C++)
  • w funkcjach takich zawsze jako pierwszy parametr występuje niejawnie wskaźnik na obiekt klasy (this) wywołujący zadaną metodę
  • funkcja o stałej liczbie argumentów:
    • sama jest odpowiedzialna za posprzątanie stosu
    • przy Microsoft C++ Compiler, wskaźnik na obiekt klasy (this) jest przekazywany przez rejestr ECX
  • funkcja o zmiennej liczbie argumentów:
    • to wywołujący jest odpowiedzialny za posprzątanie stosu
    • w tym miejscu zachowuje się dokładnie jak cdecl - wszystkie argumenty są odkładane i przekazywane przez stos, razem ze wskaźnikiem na obiekt klasy (this)
  • nazwy funkcji nie są zmieniane


Przy tworzeniu własnej witryny niezbędnym może okazać się posiadanie odpowiednich zasobów wizualnych. Jeśli nie jesteśmy zawodowymi grafikami, czasem lepiej posiłkować się dostępnymi w sieci darmowymi (głównie rozpowszechnianymi na bazie licencji Creative Commons) zbiorami ikonek:

Inne katalogi:



18 czerwca na XI spotkaniu Wrocławskiej Grupy .NET przedstawiłem tę oto prezentację. Omówiłem w niej zbiór narzędzi, który stanowi uzupełnienie Visual Studio i jest wręcz ‘niezbędnikiem’ podczas codziennej pracy programisty .NET.

Materiały z sesji pobrać można tutaj.



20 marca na VIII spotkaniu Wrocławskiej Grupy .NET w małej salce na Politechnice Wrocławskiej zaprezentowałem możliwości pisania skryptów MS Build. Prócz historii, podstaw składni i najprostszych przypadków użycia, zobaczyć można było rozszerzanie i zadania społeczności (community) na swój sposób widzącej zadania związane z przetwarzaniem plików z kodem i zasobami.

Materiały można pobrać tutaj.



 

InstallFest - Wrocław22-go stycznia na Uniwersytecie Wrocławskim miało miejsce wydarzenie organizowane przez Wrocławską Grupę .NET (wrocnet.org). Jego celem była promocja nowej wersji wydanego na dniach Visual Studio 2008. Brawa dla dzielnych, młodych organizatorów.

Ja na tej imprezie byłem, miód i wino szklankami piłem, a nawet miałem okazję poprowadzić sesję. Niestety było to moje pierwsze publiczne wystąpienie przed tak dużą publicznością. Mimo wszystko wspominam je mile.

Materiały można pobrać tutaj.



sty
01

Start tej strony

by Paweł | Tags:

Otwarcie tego portalu wiąże się z kilkoma istotnymi dla mnie wydarzeniami:

  • coraz słabsza pamięć powoduje, że ulatują mi z głowy w niebyt różne sztuczki programistyczne, które stosowałem niedawno, a próba ich odtworzenia zajmuje znacząco zbyt wiele czasu
  • CMS dodaje od siebie opcję przeszukiwania i ułatwia zdecydowanie dostęp również innym zainteresowanym
  • utrzymywanie listy 'ulubionych' do ciekawych narzędzi, blogów oraz innych portali jest coraz bardziej kłopotliwe wraz ze wzrostem liczby używanych komputerów
  • chcąc aktywnie uczestniczyć w życiu Wrocławskiej Grupy .NET (wrocnet.org), rozwijanie swoich umiejętności dziennikarskich jest mile widziane.

 

Zamieszczane materiały będą oscylowały w okolicach programowania i projektowania systemów informatycznych (C/C++, C#, ASP.NET), prowadzonych darmowych projektach oraz sesjach prowadzonych we wspomnianej Wrocławskiej Grupie.

 

Zapraszam do środka.

   Paweł Hofman



Autor

Paweł Hofman [CodeTitans]

ASP.NET
C/C++, C#, Objective-C
SQL

License and Disclaimer

Moje Gry i Aplikacje

Zobacz mnie na GoldenLine

Zobacz mnie na LinkedIn
Supported by Polish SQL Server User Group (PLSSUG)

Supported by WrocNet.org

Zine.net.pl

Wpisy

Projekty

Moje projekty open-source:

Sign in