0×06. Symbian C++, Błędy, CleanupStack

W poprzednim wpisie został wyjaśniony mechanizm wychodzenia z funkcji (Leave) oraz sposoby jego przechwytywania. Teraz należy zwrócić uwagę co się dzieje ze wszystkimi wskaźnikami, które zostały zainicjowane przed takim wyjściem – otóż jeżeli zostanie on usunięty, natomiast miejsce w pamięci nadal jest zajęte – tracimy bezpowrotnie taki obszar – następuje wyciek pamięci.

Co w takim wypadku możemy zrobić? Możemy, a raczej powinniśmy zastosować CleanupStack.


CleanupStack

CleanupStack przydaje się w sytuacjach, gdy po zaalokowaniu pamięci na dany obiekt, funkcja może wywołać Leave nie dochodząc do momentu w którym uprzednio stworzony obiekt jest poprawnie usuwany.

void Klasa::FunkcjaL()
{
TInt * i = new (ELeave) TInt;
delete i;
}

Klasa * w = new (ELeave) Klasa;
w->FunkcjaL();
delete w;

W powyższym przykładzie, funkcja FunkcjaL() alokuje pamięć, ale może także wyjść (wywołać Leave). Warto zauważyć, że ten kawałek kodu może się posypać w dwóch miejscach – po pierwsze przy alokacji obiektu klasy Klasa może coś pójść nie tak, ale w takim przypadku nic złego dla pamięci się nie dzieje. Po drugie w przypadku alokacji obiektu TInt w funkcji FunkcjaL() – jeśli funkcja wyjdzie to wskaźnik na obiekt Klasa może nigdy nie zostać usunięty z pamięci – następuje wyciek.

Bardzo prostym rozwiązaniem jest użycie w tym przypadku CleanupStack. Wszystkie wskaźniki obiektów, które chcemy zabezpieczyć muszą wylądować na tym stosie.

Klasa * w = new (ELeave) Klasa;
CleanupStack::PushL(w);
w->FunkcjaL();
CleanupStack:PopAndDestroy(w);

W takim przypadku, od razu po alokacji pamięci dla obiektu w następuje zachowanie tego wskaźnika na CleanupStack. W momencie, gdy FunkcjaL() zakończy swe działanie nie powodując żadnego błędu, funkcja CleanupStack::PopAndDestroy(w) zdejmuje ten wskaźnik od razu go niszcząc. Natomiast jeżeli FunkcjaL() wyjdzie, wtedy jako część procesu czyszczenia wszystkie obiekty znajdujące się na CleanupStack są poprawnie usuwane.

Istnieje kilka wariacji funkcji zdejmujących z CleanupStack:

  • CleanupStack:Pop() – zdejmuje ze stosu ostatnio położony wskaźnik
  • CleanupStack:Pop(2) – zdejmuje ze stosu ostatnie dwa położone wskaźniki
  • CleanupStack:Pop(wsk) – zdejmuje ze stosu i sprawdza czy jest to wsk

Istnieją także funkcje specjalnie dla klas R: CleanupClosePushL() – przy czyszczeniu wywołuje Close() dla obiektu, CleanupReleasePushL()Release(), CleanupDeletePushL()Delete().

Kilka ważnych uwag: nie należy odkładać zmiennych składowych na CleanupStack (zmienne rozpoczynające się od i – łatwo stwierdzić); funkcje kończące się literką C odkładają na stos. Nie należy nadużywać tego mechanizmu i kłaść na CleanupStack tylko te wskaźniki, w których pomiędzy stworzeniem a usunięciem może wystąpić Leave.

Również jak i w poprzedniej części odsyłam do postu na polskim forum Symbiana, który tłumaczy ten mechanizm: CleanupStack – czyli sprzątamy po sobie.

0×05. Symbian C++, Błędy, TRAP(D), Leave

Pokrótce mówiąc, mechanizm Leave służy do wychodzenia z funkcji, natomiast TRAP oraz TRAPD do przechwytywania tych wyjść, przy czym używanie przechwytywania nie jest zalecane ze względu na ich szybkość (a raczej nie-szybkość) działania oraz pamięciożerność.


TRAP(D)

Proste wyjaśnienie różnic pomiędzy TRAP oraz TRAPD – ten drugi zajmuje się od razu deklaracją zmiennej; przykład użycia TRAPD:

TRAPD(err, funkcjaL());

oraz przykład użycia TRAP

TInt err;
TRAP(err, funkcjaL());

Jak widać, w przypadku wersji TRAPD kod skraca się o jedną linijkę. Warto tutaj zauważyć, iż w przypadku gdy nie zastosujemy żadnego przechwycenia w programie, system zrobi to za nas.

Leave

Od razu przedstawiam kilka możliwych wersji tej funkcji:

  • User::Leave()
    • Wyjście z funkcji
  • User::Leave(kodBłędu)
    • Wyjście z funkcji z kodem błędu (jest przekazywany do TRAP(D))
  • User::LeaveIfError(kodBłędu)
    • Wyjście z funkcji tylko w przypadku gdy kodBłędu jest negatywny (mniejszy od 0, wszystkie błędy są wartościami ujemnymi)
  • User::LeaveNoMemory()
    • Odpowiednik User::Leave(KErrNoMemory)
  • User::LeaveIfNull(wskaźnik)
    • Wychodzi z funkcji z KErrNoMemory jeśli przekazany wskaźnik jest NULL

Bardzo ładnie zostało wyjaśnione to na polskim forum Symbiana, a dokładniej w poście użytkownika Pinio (do czego odsyłam, gdyż nie ma sensu dublować czegoś, co już zostało napisane).

0×04. Symbian C++, Błędy, Panics

Zacznę od informacji, która z pewnością może ucieszyć programistów C++. Otóż od Symbian OS 8.1 możliwe jest użycie mechanizmów przechwytywania wyjątkow znanych z języka C++, chociaż takie podejście do sprawy nie jest zalecane. Twórcy systemu namawiają do pozostania przy bardziej przetestowanym, bogatszym i zaimplementowanym w systemie od pierwszej wersji mechaniźmie walki z błędami.


Błędy Panics

Takim określeniem nazywane są błędy programistów. W sytuacji, gdy piszemy program z błędem, najlepszym wyjściem, które system może dla nas zrobić jest unicestwienie uruchomionej aplikacji najszybciej jak tylko błąd zostanie wykryty, z mniej lub bardziej dokładniejszymi informacjami o tym problemie. Podstawową używaną tutaj funkcją jest User::Panic(panicCategory, integer), gdzie panicCategory powinien być maksymalnie 16 znakowym określeniem błędu, integer natomiast 32-bitowym numerem błędu. Powszechnym sposobem używania Panics jest użycie makr __ASSERT_DEBUG oraz __ASSERT_ALWAYS; pierwszy jest kompilowany w wersji Debug, drugi w wersji Debug jak również i przy kompilowaniu wersji finalnej. Poniższy przykład obrazuje użycie opisanych makr:

void CMyClass::Foo(TInt aIndex)
{
        __ASSERT_ALWAYS(aIndex > 0, Panic(_L("Błąd typu Panic"), 11));
}

Prototyp funkcji wygląda jak pokazano poniżej: __ASSERT_ALWAYS(warunek, wyrażenie); kiedy to wyrażenie jest wykonane gdy warunek nie jest prawdą (odsyłam do 0×02. Symbian C++, Typy danych, gdzie zapisałem wzmiankę o porównywaniu typów prawda/fałsz). W tym przypadku Panic zostanie wywołane gdy aIndex będzie wartością mniejszą bądź równą zero, natomiast błąd zwrócony będzie treści „Błąd typu Panic” (_L() musi być używane do przekazywania własnych treści, w następnych częściach zostanie to wyjaśnione) o kodzie 11.

0×03. Symbian C++, Konwencja nazewnictwa

Symbian C++ jest językiem bardzo restrykcyjnym. Twórcy starali się ustandaryzować wszystko, włączanie z odpowiednim nazewnictwem w kodzie. A wszystko to między innymi, aby uniknąć błędów (np. wycieków pamięci) które są najdotkliwszymi błędami dla urządzeń posiadających małą ilość pamięci. Musimy pamiętać, że projektujemy właśnie dla takich urządzeń, gdzie pamięć jest ograniczona, a wszelkie rebooty następują o wiele rzadziej niż w przypadku komputerów klasy PC.

W poprzedniej notce zaprezentowałem w jaki sposób oznaczane są typy danych, dla przypomniania – nazwę typu poprzedza duża litera T (od Type), natomiast zmienne które odpowiadają unsigned posiadają przed nazwą typu (ale po T) dużą literę U (od unsigned). Poniżej przedstawiam podstawową konwencje nazewnictwa (na dobry początek ;)), której bardzo dobrze się trzymać:

  • Nazwy klas (prefiksy):
    • T – typy
      • Klasy T nie posiadają destruktora, występują w sposób jak typy wbudowane.
    • C – klasy
      • Klasy C to klasy dziedziczące po CBase.
    • R – zasoby
      • Klasy R to wszystkie klasy pośrednie (proxy) pomiędzy obiektami znajdującymi się gdzieś indziej.
    • M – interfejsy (Mixin)
      • Klasy M są interfejsami składającymi się z funkcji wirtualnych.
  • Nazwy danych (prefiksy)
    • E – stałe typów wyliczeniowych
      • Stała typu wyliczeniowego, powinna być składową stałej o nazwie rozpoczynającej się od T
    • K – stałe
      • Stałe. Po prostu.
    • i – zmienne składowe
      • Każda nie-statyczna zmienna składowa (i od instance).
    • a – argumenty
      • Wszystkie zmienne deklarowane jako argumenty.
  • Nazwy funkcji (sufiksy)
    • L – funkcje, które mogą leaveować (leaveowanie zostanie wyjaśnione później).
    • C – funkcje, które zostawiają coś na Cleanup Stacku (Cleanup Stack zostanie wyjaśniony później).
  • Nazwy makr
    • Pisane dużymi literami, podkreślenia zamiast spacji.
  • Symbole wbudowane
    • Pisane z podwójnym podkreśleniem jako prefiks oraz sufiks.

Ufff, trochę tego jest. W ten sposób są zapisane biblioteki, więc dobrze jest sobie to wszystko zapamiętać, w późniejszych etapach będzie to umożliwiało łatwe rozpoznanie co użyć do zabezpieczenia danej klasy lub metody, czego unikać przy wkładaniu na Cleanup Stack, etc.

Następne notki będą traktowały o mechanizmie obsługi błędów/wyjątków, co jest chyba najważniejszym tematem w świecie Symbiana.

0×02. Symbian C++, Typy danych

W każdym języku programowania istnieją typy danych. W przypadku Symbian C++ niewskazane jest używanie typów znanych z C++ (int, char, etc.) aczkolwiek istnieje taka możliwość. W dalszej części wyjaśnię dlaczego. Pisząc o typach danych muszę nadmienić, iż nomenklatura Symbiana nakazuje trzymania się pewnej konwencji nazewnictwa (co będzie tematem następnego wpisu). I tak, typy danych (łatwe do zapamiętania) zaczynają się od dużej litery T (od Type). Przechodząc do sedna, są to:

  • TInt8, TUInt8 – zmienna całkowita 8-bitowa oraz jej odpowiednik typu unsigned
  • TInt16, TUInt16 – analogicznie j.w., ale 16-bitowa
  • TInt32, TUint32 – j.w., ale 32-bitowa
  • TInt, TUInt – j.w., 32-bitowa
  • TInt64 – zmienna całkowita 64-bitowa, w praktyce przechowywana jako 2 zmienne 32-bitowe
  • TReal32 – zmienna zmiennoprzecinkowa o podwójnej precyzji 32-bitowa
  • TReal, TReal64 – j.w., ale 64-bitowa
  • TText8, TText16 – zmienne tekstowe (odpowiednikami w C++ są odpowiednio – unsigned char oraz unsigned short int)
  • TBool – zmienne booleanowskie
  • TAny – odpowiednik void z C++, najczęściej używany jako TAny *

W przypadku zmiennych boolean prawda oraz fałsz programowo są oznaczane odpowiednio jako ETrue oraz EFalse. Tutaj mała uwaga – w C++ wszystko co nie jest zerem uznawane jest za prawdę, natomiast w Symbian C++ ETrue odpowiada za wartość 1. Dlatego zamiast pisać:

TBool b = Funkcja();
if (b == ETrue) { ... }

należy porównywać

TBool b = Funkcja();
if (b) { ... }

Teraz wypada wyjaśnić dlaczego akurat takie typy a nie standardowe… Otóż wszyscy programiści C++ na pewno mają na uwadze różnice w rozmiarze typów zmiennych w przypadku różnych platform i/lub różnych kompilatorów. Z uwagi, że pisząc aplikacje na Symbian OS należy uwzględnić różne telefony (również kompilatory, środowiska), stosując typy zmiennych zaprezentowane w liście powyżej mamy pewność, iż zawsze będą takie jakie mają być. Jedynym odstępstwem od tej reguły jest zwracany typ void przez funkcje (w przypadku deklarowania wskaźników typu pustego, należy posługiwać się typem TAny).

Na tym zakończę część drugą, może informacji nowych dużo nie ma (w porównaniu z C++), ale są to fundamenty które trzeba zapamiętać.

0×01. Wstęp. Symbian OS, Symbian C++

Materiałów o Symbianie jak i programowaniu w tym systemie jest mnóstwo. Niestety w zdecydowanej większości są to materiały anglojęzyczne, a z tego względu początek zabawy w tworzeniu aplikacji na Symbiana może być bardzo trudny dla osób, które wcześniej nie miały styczności z anglojęzyczną nomenklaturą stosowaną w tego typu publikacjach. Jest to pierwszy powód, dla którego chciałbym wzbogacić rodaków o minimalną pomoc, mając nadzieję że kolejne wpisy się choć trochę przydadzą 😉 Drugim powodem jest moja praca inżynierska, której podstawą jest właśnie aplikacja na urządzenia mobilne, które działają pod kontrolą systemu Symbian. Może w którymś z kolejnych wpisów napiszę coś więcej na ten temat, a teraz przejdźmy do sedna. Albo – jak to zwykle bywa – do historii 🙂


Krótka historia

Symbian powstał w roku 1998 jako ewolucja systemu EPOC, oryginalnie tworzonego przez firmę Psion. Nokia oraz Ericsson wraz z w/w firmą są uznawani za rodziców tego systemu. Kolejnymi firmami, które dołączyły do spółki są: Panasonic (1999), Samsung (2002), Siemens (2002) oraz Sony Ericsson (2001). Również i Motorola (1998) znalazła się w spółce, chociaż po pewnym czasie zrezygnowała z udziałów. Według danych Nokia obecne udziały przedstawiają się następująco:

  1. Nokia – 47.9%
  2. Ericsson – 15.6%
  3. Sony Ericsson – 13.1%
  4. Panasonic – 10.5%
  5. Siemens – 8.4%
  6. Samsung – 4.5%

Symbian OS

Symbian OS został zaprojektowany aby działać na małych, przenośnych, zasilanych bateryjnie urządzeniach, posiadających 32-bitowe jednostki CPU, taktowane niskimi częstotliwościami. Dzisiejsze systemy działają na architekturach XScale, ARM9 oraz ARM11, natomiast starsze urządzenia napędzane są przez ARM7. System operacyjny jest zapisany w pamięci ROM. Nie zagłębiając się w szczegóły techniczne samego systemu operacyjnego (jednak czasami będzie trzeba) przejdźmy do drugiej części…

Symbian C++

Termin Symbian C++ odnosi się do specyficznej odmiany języka C++, wraz z towarzyszącymi mu Frameworkami używanymi przez Symbiana. Symbian C++ znacząco różni się od powszechniejszego C++, a różnice te mogą wynikać z platform, na które wskazują obydwa języki, jak również i doświadczenia z przeszłości (Symbian jest przecież kontynuacją systemu operacyjnego EPOC firmy Psion, którego pierwsze wersje powstały w latach 80.). Więc osoby które przypuszczały że różnice będą niewielkie lub ich nie będzie wcale na pewno się rozczarowały. Największym chyba odstępstwem (moim zdaniem) jest zupełnie inny mechanizm wyjątków. Wkrótce więcej o tym.

Posłowie

Części moich wpisów będą luźnymi tłumaczeniami różnych książek, z którymi miałem okazję się zapoznać, a także informacjami znalezionymi w Sieci. Lista książek, tudzież publikacji, które wpadły w moje ręce:

  • Symbian OS Basics
  • Developing Software for Symbian OS
  • Symbian OS C++ for Mobile Phones
  • The Symbian OS Architecture Sourcebook
  • Developing Series 60 Applications: A Guide for Symbian OS C++ Developers
  • Programming for the Series 60 Platform and Symbian OS
  • Smartphone Operating System Concepts with Symbian OS
  • Symbian OS Communications Programming
  • Carbide.C++: Introductory White Paper

Do zobaczenia w następnej części…

PHP vs. ASP.NET

Hmm, no to zaczynam reaktywację joggera po raz 3;-) Ciekawe czy tym razem coś więcej wypali… Tyle tytułem wstępu do wstępu, reakatywację czas zacząć…

Ostatnio dostałem w ręce 2 płytki Microsoftu – .NET Starter Kit 2006/2007 oraz IT Academic Day – i przyznam szczerze że zamieszczone na nich prezentacje dotyczące .NET Framework oraz pochodnych (m.in. ASP.NET) bardzo mnie zaciekawiły. Wszystko pięknie, elegancko wytłumaczone, webcasty, screencasty, prezentacje multimedialne – wszystko cacy. I tak mnie to jakoś poruszyło, że postanowiłem przeprowadzić małe porównanie między nadzwyczaj popularnym w dzisiejszych czasach PHP oraz próbującym zdobyć rynek ASP.NET Microsoftu. I z tego porównania (jeśli można to tak nazwać) wyszło coś takiego…

1. Serwery WWW

Tak samo jak różnią się oba języki tak też różnią się platformy na których działają. PHP, można powiedzieć – po poprawnej instalacji zadziała zawsze i wszędzie (Apache, IIS), czego niestety (albo i stety) nie można powiedzieć o jego konkurencie – ASP.NET. Z uwagi na to, że korzysta on z .NET Frameworka działa tylko w środowisku Windows, i to na serwerze Microsoftu – IIS. Tutaj pewnie każdy znający się na sprawie zapyta co z Apachowym mod_mono? Jakby na ten projekt nie patrzeć – inicjatywa jest genialna dla rozpowszechniania ASP.NET na platformy linuksowe, ale trzeba przyznać że do konkurowania z IIS dużo jej jeszcze brakuje. Jest jeszcze oczywiście Perlowski Apache::ASP, ale on dodaje funkcjonalność dokumentów ASP (nie ASP.NET) pisanych w Perlu. Istnieje inny moduł do Apache – mod_aspdotnet (niestety nierozwijany od jakiegoś czasu), który doskonale sprawdza się przy uruchamianiu aplikacji pisanych pod kontrolą .NET Framework 1.0 w systemach Windows (z .NET Framework 2.0 ma już częste problemy). Jeszcze innym rozwiązaniem jest Chilisoft firmy SUN (dokładniej Sun Java System Active Server Pages), któremu się niestety bliżej nie przyglądałem. No i w końcu chyba ostatnie rozwiązanie umożliwiające bezproblemowe uruchomienie aplikacji ASP.NET (nawet w wersji Framework 2.0) na Apache to serwer Cassini (Apache może ładnie przekazywać chwilowo kontrole Cassini – Proxy), lecz nie sprawdzi się to dla sympatyków ASP.NET AJAX – przeglądarka będzie przeładowywać stronę za każdym razem.

2. Bezpieczeństwo

Sprawa bezpieczeństwa zdecydowanie dodaje punktów ASP.NET. Rozpoczynając od podszewki, czyli od webserwera – IIS wygrywa. Wystarczy spojrzeć na porównanie ilości znalezionych bugów w obu serwerach (IIS oraz Apache) – po wprowadzaniu IIS 6.0 w 2004 roku w pierwszym wykryto 11 błędów, natomiast w drugim 30. To samo się tyczy PHP oraz ASP.NET – mniej łat zostało wypuszczonych właśnie dla produktu Microsoftowego, natomiast patrząc na aplikacje internetowe – 43% wszystkich luk znalezionych w sieci w 2006 roku należało do PHP. Zresztą, błędy PHP są na tyle popularne, iż każdy kto potrafi korzystać z jedynej słusznej wyszukiwarki i choć trochę zna tenże język będzie potrafił przynajmniej część z nich wykorzystać – pozwolę sobie w tym miejscu przytoczyć linka do takiego małego zestawienia: http://albi.xve.pl/2007/02/21/najpopularniejsze-ataki-w-php/ – mam nadzieję, że autor nie będzie zły 😉 Natomiast jeżeli chodzi o błędy w aplikacjach .NET to już trudniej cokolwiek znaleźć, oraz – co ważniejsze – nie są tak bardzo spopularyzowane (w sensie nienajlepszych skryptów, koderów, itp.).

3. Kod

Przechodzimy chyba już do sedna sprawy, najbardziej istotnej rzeczy dla większej rzeszy webmasterów – kod. Tutaj również jestem skłonny przyznać wszystkie punkty dla produktu stajni MS. Niektórzy mogą uznać to za wadę (osobiście nie mam zdania) – w ASP.NET programista został obdarowany kontrolkami które zdecydowanie zmniejszają czas poświęcony na pisanie kodu. Z tego też względu prawdopodobieństwo wystąpienia luki w aplikacji zmniejsza się ogromnie. Dodatkowo dostajemy możliwość pisania kodu w VB lub C#, więc nie jesteśmy ograniczeni do jednego stylu, który zwykł się zmieniać wraz z kolejnymi wersjami PHP. ASP.NET jest do granic możliwości obiektowe oraz posiada jednoznacznie sformułowane funkcje (PHP tutaj dostaje po tyłku jak nikt inny – funkcje typu str_replace, później strlen nie dają dobrego obrazu językowi który – pokuszę się o stwierdzenie – zdominował sieć). Z drugiej strony istnieje sporo dodatkowych klas rozszerzających możliwości PHP, jednak łatwość tworzenia takiego skryptu jest – jak już wspomniałem wcześniej – zdradliwa. Dodatkowo programista ASP.NET posiada możliwość projektowania wizualnego, co w przypadku PHP pozostaje (na razie) tylko jako marzenie.

4. Popularność

Wszyscy wiemy, że popularność języka PHP jest ogromna. Ale, jeśliby się wgłębić w rzeczywistą znajomość pisania aplikacji w tym języku, dużej liczbie osób tylko wydaje się, że go zna, że potrafi w nim coś napisać, a już na pewno coś co z bezpieczeństwem nie ma nic wspólnego. Podręczniki oraz opisy funkcji PHP są łatwo dostępne, ale tylko tyle – istnieje niewiele osób które potrafią pomóc jeśli piszesz coś naprawdę zaawansowanego i napotkałeś nie lada problem. Nie mówię, że w ASP.NET tak nie jest – ale istnieje wiele serwisów internetowych udostępniających mnóstwo informacji, kodów, przykładów, opisów, a nawet i materiałów do nauczania (webcasty, prezentacje, e-learning), natomiast gdzie dla PHP coś takiego ma miejsce? Hmm, chyba się zagalopowałem… ale chciałem spróbować otworzyć oczy ludziom którzy uważają że wszystko co wychodzi ze znakiem MS jest be 😉

5. Hosting

Jest to jedna z niewielu rzeczy, przemawiająca za PHP – jest tylko garstka serwisów internetowych (w Polsce bodajże http://hostedwindows.pl/ oraz http://ms.windows-hosting.pl), które oferują bezpłatny hosting ASP.NET, czego o niekomercyjnym „odpowiedniku” powiedzieć nie można – praktycznie każde konto www posiada obsługę tegoż języka.

6. Podsumowanie

Próbując podsumować powyższe wypociny dochodzę do wniosku, że nie da się jednoznacznie stwierdzić który język jest lepszy, który jest przyszłościowy, w który webmasterzy powinni zainwestować, który za parę lat zrewolucjonizuje sieć, a który będzie go gonił. Są wady i zalety – jedną z większych wad PHP w porównaniu do ASP.NET jest jego bezpieczeństwo oraz styl tworzenia samych aplikacji (to ostatnie może źle ująłem). Jeżeli jednak spojrzeć w drugą stronę, czyli ASP.NET w porównaniu do PHP – znikoma popularność, darmowy webhosting czy w pewnym sensie samo pisanie kodu – czyli to, co jest niemal podstawą w rozwoju programistycznym. Osobiście poznaję PHP od paru dobrych lat, ale nie ukrywam również że jestem zafascynowany całym .NET 🙂

No, to dziękuję za uwagę, dobranoc 😉