Port równoległy LPT w C na Linux – obsługa portu i sterowanie diodami LED

Port LPT bardzo dobrze nadaje się do pierwszych prób skomunikowania komputera z zewnętrzną elektroniką. Jest to możliwe dzięki temu, że w przeciwieństwie do inny portów (np. COM, USB, etc.) możemy ustawić dane wyjście w stan wysoki (lub niski) i stan ten będzie się utrzymywać.

Zacznijmy od określenia, które wyprowadzenia będą dla nas interesujące. Pomoże w tym poniższa ilustracja z Wikipedii.

lpt_pint

Czytaj całość...

Pointer to Multidimensional Array Casting – C++ – Rzutowanie wskaźnika na tablicę wielowymiarową

Często w C oraz C++ zachodzi potrzeba rzutowania wskaźnika np. int* na tablicę jakiegoś konkretnego rozmiaru np. int a[2][2]. Przykładowy przebieg sytuacji wygląda tak:

int size = 2;
int graph[2][2] =
{0, 1,
 1, 1};
int(*ptr)[size] = (int(*)[size])graph;
cout < < ptr[1][1];
Czytaj całość...

Wzorce programistyczne – Fabryka abstrakcyjna (Abstract Factory) w C++ i PHP

Wzorzec programistyczny typu Abstract Factory jest jednym ze wzorców służących do tworzenia obiektów. Jest to rozszerzony przypadek innego wzorca programistycznego – klasycznej Fabryki. W klasycznym wzorcu typu Fabryka, klasa fabrykująca posiadała metody, które tworzyły instancje obiektów. Możliwe było dziedziczenie z takowej Fabryki w celu nadpisywania odpowiednich metod i tym samym zmienianie poszczególnych sposobów kreacji. W przypadku Fabryki Abstrakcyjnej posuwamy się o jeden krok wyżej. Mamy kilka Fabryk udostępniających ten sam interface i w zależności od okoliczności, powołujemy do życia inną Fabrykę służącą użytkownikowi do kreacji obiektów. Użytkownik jest odseparowany i nie informowany o faktycznych typach obiektów, a jedynie posługuje się wspólnym interfacem.

Czytaj całość...

Wzorce programistyczne – Dekorator (Decorator) w C++ i PHP

Wzorzec programistyczny typu Dekorator jest bardzo wygodnym sposobem wzbogacania (dekorowania) obiektu w czasie rzeczywistym. Efekt ten jest osiągany poprzez wrappowanie instancji obiektu w kolejne instancje, które dodają do obiektu bazowego kolejne funkcjonalności.

Wzorzec opiszę na 2 przykładach. Pierwszy będzie to przykład oparty o PHP i zaczerpnięty z frameworków do tworzenia stron WWW. Będziemy chcieli osiągnąć efekt wrapowania tagów HTML w kolejne tagi. Dla przykładu:

$box1 = new Div(new Link( new Image() ));
$box1->printOut();

Powyższy kod ma dać w efekcie wydruk na ekranie w postaci:

<div><a><img /></a></div>

Czytaj całość...

Kompilacja, linkowanie, biblioteki statyczne i dynamiczne

Wielu programistów, mimo że bardzo dobrze obeznanych z pisaniem programów, nie do końca orientuje się, co za magia stoi za linkowaniem bibliotek zewnętrznych do ich aplikacji, a także jest trochę wystraszona, gdy ma takową bibliotekę dołączyć do swojego projektu, gdy nie ma dokładnego opisu jak to zrobić.

Czytaj całość...

Borland C++ Compiler 5.5 – kompilacja, linkowanie i konfiguracja bcc32.cfg

Borland C++ Compiler 5.5 to znany kompilator dla języka C++. Darmowość oraz kompatybilność z bibliotekami statycznymi *.lib to spore zalety. Konfiguracja dokonywana jest poprzez odpowiednie skonfigurowanie pliku konfiguracyjnego oraz ustawienie PATH.

Czytaj całość...

Tutorial do Xerces-C++ 3 – cz. 1: Instalacja, konfiguracja i pierwszy projekt

Xerces-C++ to darmowa biblioteka do obsługi języka XML rozwijana przez Apache Software Foundation. Tak jak wszystkie produkty spod marki ASF prezentuje bardzo wysoki poziom i szeroki wachlarz funkcjonalności. Jednakże, co dziwne w przypadku takich produktów, ciężko o jakiś prosty tutorial dla początkujących.

Czytaj całość...

Kontenery asocjacyjne w C++ STL

Kontener to struktura danych umożliwiająca przechowywanie w zorganizowany sposób innych obiektów. Natywne biblioteki STL z C++ udostępniają wysokiej jakości kontenery zróźnicowane pod względem swoich właściwości. Kontenery w STL oparte są o szablony klasy (template class).

Kontenery asocjacyjne to specjalny rodzaj kontenerów, których zadaniem jest umożliwienie dostępu do przechowywanych elementów za pomocą kluczy, które na nie wskazują, w przeciwieństwie do kontenerów sekwencyjnych, których zadaniem było umożliwienie dostępu do elementów za pośrednictwem absolutnych lub relatywnych indeksów pozycji.

Czytaj całość...

Kontenery sekwencyjne w C++ STL

Kontener to struktura danych umożliwiająca przechowywanie w zorganizowany sposób innych obiektów. Natywne biblioteki STL z C++ udostępniają wysokiej jakości kontenery zróźnicowane pod względem swoich właściwości. Kontenery w STL oparte są o szablony klasy (template class).

Kontenery sekwencyjne to specjalny rodzaj kontenerów, których zadaniem jest przechowywanie innych elementów w sposób zachowujący informacje o kolejności tych elemetów, co przekłada się na dostęp do tych elementów za pomocą pozycji relatywnej (iterator) lub absolutnej (indeks).

Czytaj całość...

Różnice między C oraz C++

Język C++ powstał na bazie C. Oba języki utrzymują prawie całkowitą kompatyblność, jednak jest kilka aspektów, którymi się różnia. Prowadzi to do sytuacji, że nie zawsze daje się bezproblemowo skompilować kod napisany w jednym języku przy użyciu kompilatora do drugiego. Niniejszy tekst opisuje zwięźle różnice, o których powinien pamiętać programista.

Czytaj całość...

Wskaźnik na funkcję w C++

W C++ wskaźnik na funkcję ma specyficzną budowę trudną do zapamiętania. Na forum portalu 4programmers pojawiła się recepta użytkownika Azarien na to, jak można sobie ułatwić utrwalenie w pamięci budowy owych wskaźników:

  • tworzymy nagłówek normalnej funkcji
  • void foo(void *ptr, int size)

  • przy czym nazwy parametrów pomijamy
  • void foo(void*,int)

  • następnie nazwę funkcji (stanie się ona nazwą zmiennej lub parametru) poprzedzamy gwiazdką i bierzemy w nawias
  • void (*foo)(void*,int)

  • jeżeli foo ma być zmienną, zakańczamy średnikiem
  • void (*foo)(void*,int);

  • jeżeli parametrem funkcji, po prostu wklejamy w listę parametrów
  • void Function(void (*foo)(void*,int)) {}

  • jeżeli nazwą nowego typu, poprzedzamy typedefem
  • typedef void (*foo)(void*,int);

  • a jeżeli chcemy mieć parametr funkcji jako sam typ bez nazwy parametru, w nazwie zostaje nawias i gwiazdka
  • void Function(void (*)(void*,int));

Czytaj całość...

Stronicowanie vs segmentacja

Dogłębna znajomość pojęć segmentacji i stronicowanie nie jest konieczna dla zwykłego zjadacza kodu, jednak każdemu może się przydać zrozumienie o co chodzi w tych dwóch pojęciach. Postaram się bardzo skrótowo i w bardzo uproszczony sposób pokazać, o co chodzi.

segmentacja vs stronicowanie

Z lewej strony rysunku mamy przykładowy kod, w przykładowym języku programowania. Jest to naprzemienne tworzenie stringa i jego wyświetlanie. Tak to wygląda w oczach programisty. I teraz…

Segmentacja jest pokazana na środkowym rysunku. Kompilator podzielił nasz program na segment danych i segment kodu. Dane programu mogą ulegać zmianie, więc znajdują się w segmencie przeznaczonym do odczytu i zapisu. Kod programu nie jest przeznaczony do modyfikacji i znajduje się w segmencie przeznaczonym tylko do odczytu. Stąd mamy pierwszy wniosek. Segmentacja zapobiega ingerowaniu w pamięć nie przeznaczoną do tego. Spójrzmy na indeksowanie komórek na środkowym rysunku. Adresowanie zaczyna się od początku dla każdego z segmentów. Stąd mamy drugi wniosek. Segmentacja ułatwia nam operowanie adresami, bo dzielimy sobie kod na kilka części adresowanych od początku.

Stronicowanie jest pokazane na prawym rysunku, który pokazuje fizyczny układ w pamięci, czyli tak jak to wygląda w kości RAM. Czerwone pola oznaczają pamięć zajętą przez inne programy. Między tymi czerwonymi polami była wolna przestrzeń, ale niewystarczająca na umieszczenie naszego programu w całości. System operacyjny powkładał nasz program gdzie się da w wolne obszary pamięci i zapamiętał tylko w jakiejś swojej tabeli, gdzie co leży, żęby móc to później wrócić jakoś do kupy. Stąd mamy wniosek odnośnie stronicowania. Stronicowanie pozwala wykorzystać małe obszary wolnej pamięci na umieszczenie w nich dużych fragmentów aplikacji.

Czytaj całość...

Duże liczby losowe w C

W dniu wczorajszym na forum 4programmers odbyła się bardzo ciekawa dyskusja na temat losowania dużych liczb w C z użyciem funkcji rand(). Wnioski z tej dyskusji mogą się przydać każdemu.

Funkcja rand() zwraca wynik w postaci dodatniej liczby typu signed int. Jest to istotne, gdyż:

  • int w zależności od platformy ma 2 bajtu lub 4 bajty
  • dodatnia liczba typu signed ma zawsze 0 na najstarszym bicie, więc de facto może przyjmować tylko połowę wartości, niż by to mogło się wydawać z liczby bitów
  • reasumując: na platfornie z sizeof(int)==2 może przyjmować wartości od 0 do 32767 (7FFFh), a na platformach z sizeof(int)==4 od 0 do 2147483647 (7FFFFFFFh)

Bardzo często konieczne jest wylosowanie większej liczby i sporo programistów zbyt lekko wykonuje sobie jakieś mnożenie lub dodawanie, aby otrzymać takową liczbę. Jest to bardzo zwodnicze i nie należy tego robić. Przykładowo, jeżeli ktoś chciałby wylosować liczbę od 0 do 1000000, mógłby wpaść na pomysł, aby zrobić to tak:

int mul = 1000000 / 32767;
int rand = mul * rand();

BŁĄD! Proszę zauważyć, że ten kod będzie losować tylko wilokrotności liczby 30. Ktoś inny mógłby zastosować bardziej wysublimowane rozwiązanie i zrobić to tak:

unsigned int most = rand();
unsigned int least = rand();
unsigned int random = ((most << 16) + least) % 1000000;

BŁĄD! Rand() daje zawsze 0 na najstarszym bicie, więc de facto daje tylko 15 bitów efektywnych. Powyższy kod pozostawia zawsze 2 bity wyzerowane. Dobrym rozwiązaniem jest poniższy kod:

long unsigned int = (rand() <<17 ) ^ (rand()<<N) ^ (rand());
gdzie za N można dać sobie dowolną liczbę z przedziału domkniętego <2,7>.

Czytaj całość...