klub sterowanie













ENTER 8/2000
























 






 




 



infoserwis

|

kiosk
|

email/www
|
technologie
|
enter extra
|
słownik
|

 

prenumerata
|

na CD










 


 







































































































infoserwis


 

subskrypcja








technologie









aktualny numer


 

spis treści


 

na krążkach








kiosk on-line








słownik










enter extra



 

internet od @ do WWW


 

cyfrowy świat


 

anatomia pc 1


 

internet praktyczny


 

komputer w firmie



 
małe sieci


 
muzyka i film


 
cudowny świat gsm








enter special


 
kopiujmy co się da


 
windows xp bez tajemnic








enter w firmie


 
programy i sprzęt








enter power


 
więcej mocy










archiwum


 

numer


 

cd










prenumerata








reklama








email/www


 

administracja


 

nowe konto


 

pomoc


 
faq








forum








redakcja







 


 















 






 


















ENTER
8/2000
klub użytkownika
poprzedni
artykuł
następny
artykuł










 
Sterowanie programem
- Marek
BartosiewiczW tej części cyklu dokładniej przypatrzymy się instrukcjom sterującym,
poznamy wbudowane typy danych z pochodnymi, a także wspomnimy o operatorach arytmetycznych i logicznych. Nabyte wiadomości
wykorzystamy do napisania prostego pseudobenchmarku, mierzącego prędkość zapisu danych przez procesor w pamięci RAM.
Kompilator C/C++ tłumaczy kod w postaci zrozumiałej dla człowieka (plik tekstowy ASCII napisany zgodnie z regułami języka C/C++) na postać strawną dla procesora (kod binarny instrukcji maszynowych). Język C został zaprojektowany jako „asembler wysokiego poziomu”, dlatego znacząca większość jego instrukcji, a także formatów danych, ma odzwierciedlenie w kodzie maszynowym. Zapewnia to sprawne i szybkie działanie tak przetłumaczonego programu. 
Jak już wiemy z poprzedniego odcinka, zanim użyjemy w naszym programie jakiejkolwiek nazwy (zmiennej, stałej, obiektu itp.), musimy poinformować kompilator o swoich zamierzeniach. Potrzebne nam obiekty definiujemy, pisząc np.:

float z1;
long int z2 = 1;

Druga linijka definiując „z2” jako zmienną typu całkowitego (32 bity) przeprowadza jej inicjalizację i nadaje wartość „1”. Deklaracja typu zmiennej, która jest reprezentowana przez liczbę całkowitą, może zostać poprzedzona modyfikatorem: „signed” (oznaczającym, że zmienna przyjmuje wartości dodatnie lub ujemne) lub „unsigned” (tylko wartości nieujemne). Tym samym mamy do wyboru (kompilator dla 32-bitowych systemów operacyjnych):




Typ
Rozmiar
Zakres


Short int
16 bitów
od –32768 do +32767


Unsigned short int
16 bitów
od 0 do 65535


int
32 bity
od –2147483648 do +2147483647


unsigned int
32 bity
od 0 do 4294967295


signed char
8 bitów
od –128 do +127


unsigned char
8 bitów
od 0 do 255





W razie wątpliwości możemy skorzystać z operatora, który zwraca rozmiar obiektu, podany jako argument, w bajtach. Nosi on nazwę „sizeof”:

cout « “Rozmiar typu int: ” 
« sizeof(int) « endl;
cout « ”Rozmiar zmiennej z1: ” 
« sizeof(z1) « endl;

Natomiast jeśli chodzi o liczby zmiennoprzecinkowe, istnieją trzy ich typy:





float
32 bity


double 
64 bity


long double
80 bitów




Pamiętajmy, że wyższa precyzja obliczeń (więcej bitów przeznaczonych dla zmiennej) okupiona jest dłuższym czasem ich trwania. Trzy typy liczb rzeczywistych pozwalają dokonać wyboru między wydajnością a dokładnością obliczeń.
Na podstawie wymienionych typów fundamentalnych możemy tworzyć tzw. typy pochodne. Najlepszym przykładem są tablice. Tworzymy (definiujemy) je w taki sposób:

float tab1[32];
int tab2[100][100];

W nawiasach kwadratowych podana jest liczba elementów danego typu, z których będzie się składać tablica. Nawiasy kwadratowe są w języku C/C++ operatorem odwołania się do określonego elementu tablicy. Pamiętajmy, że numeracja elementów zaczyna się od zera: „tab1[0]” oznacza pierwszy element tablicy zmiennych rzeczywistych, a „tab1[31]” – ostatni. Tablica „tab2” jest dwuwymiarowa: do jej obsługi potrzebne są dwa indeksy, np. „wynik = tab2[1][1] + tab2[1][2];”.
Do najczęściej używanych tablic w języku C/C++ należą łańcuchy znaków (stringi):
...
char komunikat[] = 
”To jest komunikat.”;
...
cout « komunikat « endl;
...

Zauważmy, że w definicji tablicy „komunikat” nie został wyspecyfikowany jej rozmiar. Kompilator uprości nam życie i zrobi to automatycznie, zliczając znaki występujące po prawej stronie znaku przypisania.
Pozostałe typy pochodne tworzy się za pomocą operatorów:
* – wskaźnik kierujący ku obiektowi danego typu,
& – referencja obiektu danego typu, operator pobrania adresu,
() – funkcja zwracająca wartość danego typu.
Przykłady użycia:

int i = 0; //obiekt ”int” o wartości 0
int *w1; //deklaracja wskaźnika kierującego ku ”int”
w1 = &i; //wskaźnik z1 pokazuje obiekt i
...
float wynik;
wynik = pierwiastek(x);

Wskaźnikami obiektów i referencjami, a także funkcjami, zajmiemy się dokładniej w dalszych odcinkach. Teraz wspomnimy jedynie, że nazwa tablicy jest jednocześnie wskaźnikiem jej pierwszego elementu (czyli przechowuje adres pierwszego elementu). Poprawne są więc następujące dwa sposoby odwoływania się do elementów tablicy:

int tablica[100];
...
wynik1 = tablica[7] + tablica[16];
wynik2 = *(tablica + 7) + 
*(tablica + 16);
if (wynik1 == wynik2) cout 
« ”To samo!”;
...

Pojawia się tutaj znowu gwiazdka, ale nie oznacza ona tym razem po prostu wskaźnika, lecz operator odwołania się do zawartości pamięci wskazywanej przez ten wskaźnik (w naszym przykładzie w nawiasach są liczby powodujące „przeskoczenie” o 7 lub 16 elementów „do przodu” od wskazania „tablica”). To bardzo ważne rozróżnienie: w definicji „w1” wystąpiła gwiazdka, która poinformowała kompilator, że „w1” ma być wskaźnikiem. Jeśli korzystanie ze wskaźnika w dalszej części programu odbywa się już bez tej gwiazdki, operujemy na adresie przechowywanym przez „w1”. Dopiero użycie „*w1” powoduje odczyt lub zapis zawartości pamięci wskazywanej przez „w1”.

Operatory
Język C++ został wyposażony w 56 operatorów o różnym działaniu: manipulacyjnych, arytmetycznych i logicznych. Ograniczymy się do podania jedynie najpotrzebniejszych w początkowym etapie nauki – przedstawia je tabela. Działania z operatorami o wyższym priorytecie wykonywane są przed działaniami korzystającymi z operatorów o niższym priorytecie. Wystarczy jednak zapamiętać, że działania arytmetyczne przebiegają w takiej kolejności, jaką znamy ze szkoły. W razie wątpliwości podczas pisania bardziej skomplikowanych wyrażeń używajmy nawiasów – poprawią czytelność i zagwarantują poprawne obliczenie wyrażenia.

Instrukcje sterujące
Ogólna zasada działania instrukcji sterujących polega na podejmowaniu decyzji, co do dalszego wykonywania fragmentu kodu programu, na podstawie obliczanego podczas pracy programu wyrażenia stanowiącego warunek. Wynik tych obliczeń przyjmuje jedną z dwóch wartości: „prawda” lub „fałsz”. W odróżnieniu od języka Pascal, C/C++ nie ma specjalnego typu zmiennych do przechowywania wartości logicznych (w Pascalu taką funkcję pełni typ „boolean”). Można użyć dowolnego z istniejących (np. zmienną typu „int”) lub zdefiniowanych przez programistę obiektów. Podczas kontroli warunku sprawdzana jest zawartość obiektu: jeśli okaże się różna od zera, oznacza to „prawdę”, gdy wynosi zero – „fałsz”.

Pętle
Pętla typu „for” ma postać:

for (inicjalizacja; warunek; krok)
{
...
}

Inicjalizacja to instrukcja (lub kilka instrukcji rozdzielonych przecinkami) wykonywana przed rozpoczęciem pracy pętli. Warunek to wyrażenie obliczane za każdym obiegiem pętli, przed wykonaniem instrukcji składających się na ciało pętli. Jeśli ma wartość „0”, praca pętli zostanie przerwana, w przeciwnym wypadku zostaną wykonane instrukcje wewnątrz pętli. Krokiem nazywamy instrukcję (lub kilka instrukcji) wykonywanych na koniec obiegu pętli, bezpośrednio przed powtórnym obliczeniem wyrażenia warunkowego, np. pętla

for (i = 0; i < 10; i = i + 1)

wykonana zostanie dziesięć razy.

Pętlę „do {...} while(warunek);” poznaliśmy już w poprzednim odcinku. Jak pamiętamy, wyrażenie warunkowe obliczane jest po wykonaniu (co najmniej raz) ciała pętli, a sama pętla wykonywana jest, dopóki warunek przyjmuje wartość niezerową (prawda). Jej druga forma wygląda następująco:

while(warunek) {...}

Tym razem wyrażenie warunkowe zostanie obliczone w pierwszej kolejności, przed wykonaniem ciała pętli. Jej wykonywanie zostanie przerwane, gdy warunek przyjmie wartość zero (fałsz).

Instrukcje warunkowe
Podstawową instrukcję warunkową „if” również mieliśmy okazję poznać w poprzednim spotkaniu. Drugą przydatną instrukcją tej klasy jest „switch” – dzięki niej możemy dokonać wyboru wielowariantowego:
int wybor;
...
cin » wybor;
switch (wybor)
{
case 1:
...
break;
case 2:
...
break;
case 8:
...
break;
default:
...
break;
}

Działanie instrukcji wyboru wielowariantowego: obliczane jest wyrażenie umieszczone w nawiasach po słowie „switch”. Jeśli jego wartość zgadza się z którąś z etykiet, występujących po słowach „case”, wykonywane są instrukcje zaczynające się od tej etykiety, aż do najbliższej instrukcji „break” (która powoduje wyskoczenie z instrukcji „switch”). Gdy wartość wyrażenia nie pasuje do żadnej z etykiet, wykonany zostaje blok instrukcji po słowie kluczowym „default” (ta część jest opcją, nie musi występować w każdej instrukcji „switch”), aż do najbliższego „break”.

Instrukcje pomocnicze dla instrukcji sterujących
Poznane przed chwilą „break” powoduje bezwarunkowe przerwanie instrukcji „switch”, a w wypadku użycia wewnątrz pętli (dowolnego rodzaju) natychmiast przerwie jej wykonanie. Istnieje jeszcze druga, przydatna wewnątrz pętli instrukcja: „continue”. Sprawia ona, iż zostaje przerwany aktualny obieg pętli, ale nie samo jej wykonywanie. Rozpocznie się po prostu następny jej obieg:

for (int i = 0; i < 4; i++)
{
if (i == 1) continue;
cout « i « endl;
}
W przykładzie nie zostanie wyświetlona liczba ”1”.

Teoria w praktyce
Naszym zadaniem będzie pomiar tempa, w jakim procesor zapisuje dane w pamięci. Ze względu na prędkość dzisiejszych procesorów nie można zmierzyć czasu trwania pojedynczej operacji zapisu danych, lecz wielu milionów. Aby zminimalizować wpływ pamięci cache na wynik, dane należy zapisywać w różnych lokacjach pamięci, najlepiej w kolejności rosnącej. Najprostszym rozwiązaniem jest użycie odpowiednio (w zależności od prędkości komputera) dużej tablicy liczb całkowitych.
Na płytce zamieściliśmy gotowe programy, obrazujące kolejne kroki rozbudowy naszego programu. Polecamy ich przeanalizowanie, gdyż ograniczona objętość artykułu nie pozwala na zamieszczenie całości kodu źródłowego. Pliki mają nazwy „speed.cpp”, „speed1.cpp”, „speed2.cpp”, począwszy od najprostszego (i najmniej przydatnego) rozwiązania problemu pomiaru. Wszystkie zostały wyposażone w komentarze wyjaśniające działanie poszczególnych instrukcji.
Ze względu na „nadgorliwość” kompilatora, aby otrzymać w miarę sensowne wyniki, musimy wyłączyć wszystkie optymalizacje kodu (przełącznikiem „-Od” – co zapewni nam przełożenie kodu C/C++ na maszynowy dosłownie, polecenie kompilacji przyjmie postać „bcc32 -Od program.cpp”). Na moim komputerze otrzymałem wyniki: 8 bitów – ok. 43 MB/s, 16 bitów – ok. 69 MB/s, 32 bity – ok. 80 MB/s. W zależności od prędkości komputera warto poeksperymentować z ustawieniem stałej „ile”. Właściciele szybkich maszyn muszą uważać, aby nie wstawić zbyt mało. Jeśli zmierzony czas będzie mniejszy od 1 ms, wartość zwracana przez funkcję „clock()” nie zdąży się zmienić i w wyniku późniejszych obliczeń dostaniemy komunikat „błąd dzielenia przez zero”.




Lista przydatnych operatorów


Operator Nazwa Priorytet
[] element tablicy 16
() wywołanie funkcji 16
() wyrażenie w nawiasach 16
sizeof rozmiar obiektu, typu 15
++ inkrementacja 15
– dekrementacja 15
! negacja 15
& pobranie adresu 15
* referencja wskaźnika 15
() rzutowanie 15
* mnożenie 13
/ dzielenie 13
% modulo (reszta z dzielenia) 13
+ suma 12
- różnica 12
« przesunięcie bitów w lewo 11
» przesunięcie bitów w prawo 11
< mniejsze 10
<= mniejsze lub równe 10
> większe 10
>= większe lub równe 10
== równe 9
!= nierówne 9
& iloczyn bitowy (and) 8
^ różnica symetryczna (xor) 7
| suma bitowa (or) 6
&& koniunkcja (logiczne and) 5
|| alternatywa (logiczne lub) 4
= przypisanie 3






































 
 














































































ENTER
12/2002




 






 











ENTER POWER






 







 











ENTER W FIRMIE






 







 










ENTER SPECIAL






 







 









ENTER
EXTRA






 






 








INDEKS CEN























IMPREZY




 







patronuje:




 






Seminaria StatSoft





 














KONKURSY












KRZYŻÓWKA ENTERA














 W Y N I K I:



KRZYŻÓWKA ENTERA 10'02
KOMIKS 7'02

















ANKIETA




 














Z jakiego komunikatora korzystasz najczęściej?






Gadu-Gadu




ICQ




MSN Messenger




Tlen.pl




z innego







 









   
Wyniki ankiet >>
















 












 













 





















PCkurier |
CRN |
Telenet forum |
CADCAM FORUM |
AEC forum





Copyright © 1997-2002 by LUPUS Sp. z o.o.
Polityka prywatności
































 

uwagi
odnośnie stron internetowych prosimy kierować do webmastera







 


 
 








 








Wyszukiwarka

Podobne podstrony:
automatyka i sterowanie wyklad
Sterownik dwubarwnych diod LED
Sterownik nadajnika do lowow na lisa
sterowniki programowalne plc, cz??? 3
Sterownik oswietlenia kabiny samochodu
Optymalne sterowanie i tradycyjny rachunek wariacyjny Dwuwymiarowe zagadnienie Newtona
PRZYCISKI STEROWANIA RT3
Moduł zdalnego sterowania PC 1
Sterowce latające dinozaury

więcej podobnych podstron