• Nie Znaleziono Wyników

skrcona wersja wykadowa

N/A
N/A
Protected

Academic year: 2021

Share "skrcona wersja wykadowa"

Copied!
77
0
0

Pełen tekst

(1)

Podstawy programowania

Podstawy programowania

w j

w języku C++

ęzyku C++

Funkcje i struktura programu

Wersja skrócona, tylko C++ Część piąta Roman Simiński roman.siminski@us.edu.pl www.us.edu.pl/~siminski Autor Kontakt

(2)

Pierwsza własna funkcja

Pierwsza własna funkcja

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

(3)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

Pierwsza własna funkcja — jak to działa?

Pierwsza własna funkcja — jak to działa?

» cin >> dlugosc_boku;

?

dlugosc_boku

?

(4)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

Pierwsza własna funkcja — przed wywołaniem

Pierwsza własna funkcja — przed wywołaniem

» pole = oblicz_pole_kwadratu( dlugosc_boku );

25

dlugosc_boku

?

(5)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

Pierwsza własna funkcja — wywołanie funkcji, przekazanie parametrów

Pierwsza własna funkcja — wywołanie funkcji, przekazanie parametrów

» double oblicz_pole_kwadratu( double bok )

25 dlugosc_boku 25 bok 25 ? pole

(6)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

Pierwsza własna funkcja — wykonanie funkcji

Pierwsza własna funkcja — wykonanie funkcji

» return bok * bok ;

25 dlugosc_boku 25 bok 625 ? pole

(7)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku, pole;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

pole = oblicz_pole_kwadratu( dlugosc_boku );

cout << "Pole: " << pole;

Pierwsza własna funkcja — po powrocie funkcji

Pierwsza własna funkcja — po powrocie funkcji

» cout << "Pole: " << pole;

25

dlugosc_boku

625

(8)

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

cout << "Pole: " << oblicz_pole_kwadratu( dlugosc_boku );

return EXIT_SUCCESS; }

Pierwsza własna funkcja — drobna optymalizacja

Pierwsza własna funkcja — drobna optymalizacja

Zmienna pole jest niepotrzebna, rezultat funkcji może być przekazany do strumienia wyjściowego bezpośrednio.

Zmienna pole jest niepotrzebna, rezultat funkcji może być przekazany do strumienia wyjściowego bezpośrednio.

(9)

typ_rezultatu nazwa_funkcji( lista_parametrów_formalnych ) {

ciało_funkcji }

Ogólna postać definicji funkcji

Ogólna postać definicji funkcji

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

double oblicz_obwod_kwadratu( double bok ) {

return 4 * bok; }

double oblicz_delte( double a, double b, double c ) {

(10)

A co z procedurami?

A co z procedurami?

W języku C/C++ nie występuje podział podprogramów na procedury i funkcje. Wszystkie podprogramy są funkcjami.

Istnieje jednak możliwość wykorzystywania funkcji jak procedur, bądź deklarowania funkcji tak, by przypominały procedury.

Słowo kluczowe void, będące nazwą typu, oznacza brak, nieobecność

jakiejkolwiek wartości.

Jeżeli typem rezultatu będzie typ określany słowem kluczowym void, to

oznacza, iż funkcja nie udostępnia rezultatu – staje się wtedy czymś podobnym do procedury z języka Pascal.

(11)

Jeżeli rezultat funkcji nie jest ważny? Procedura...

Jeżeli rezultat funkcji nie jest ważny? Procedura...

void wyswietl_info( void )

{

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: "; }

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; } int main() { double dlugosc_boku; wyswietl_info(); cin >> dlugosc_boku;

cout << "Pole: " << oblicz_pole_kwadratu( dlugosc_boku );

return EXIT_SUCCESS;

Zadaniem funkcji jest wyprowadzenie tekstu komunikatów. Nie potrzebuje parametrów, nie oddaje rezultatu.

Zadaniem funkcji jest wyprowadzenie tekstu komunikatów. Nie potrzebuje parametrów, nie oddaje rezultatu.Zadaniem funkcji jest wyprowadzenie tekstu komunikatów. Nie potrzebuje parametrów, nie oddaje rezultatu. Zadaniem funkcji jest wyprowadzenie tekstu komunikatów. Nie potrzebuje parametrów, nie oddaje rezultatu.

(12)

Kilka słów na temat definiowania funkcji

Kilka słów na temat definiowania funkcji

Jeżeli w miejscu listy parametrów formalnych występuje słowo kluczowe void, to oznacza, że funkcja nie posiada parametrów.

Jeżeli funkcja posiada rezultat, w ciele funkcji powinna wystąpić instrukcja

return, a po niej, wyrażenie o typie zgodnym z typem rezultatu funkcji.

Na liście parametrów formalnych, dla każdego parametru określamy jego typ.

Nawiasy po nazwie funkcji są konieczne, nawet gdy funkcja nie ma parametrów. Nawiasy występują zarówno przy definicji, deklaracji jak i przy wywołaniu

(13)

Kilka słów na temat definiowania funkcji

Kilka słów na temat definiowania funkcji

Wersja naiwna funkcji obliczania średniego spalania:

float oblicz_spalanie( float paliwo, float dystans ) {

return ( paliwo * 100 ) / dystans; }

Próba ratowania się przed dzieleniem przez zero:

float oblicz_spalanie( float paliwo, float dystans ) {

if( dystans != 0 )

return ( paliwo * 100 ) / dystans; }

(14)

Kilka słów na temat definiowania funkcji

Kilka słów na temat definiowania funkcji

Specyfikacja funkcji: oblicz średnie spalanie, ignoruj ujemne wartości

parametrów, gdy dystans jest zerowy, niech rezultat będzie równy -1, co jest sygnałem błędu.

float oblicz_spalanie( float paliwo, float dystans ) {

if( dystans == 0 )

return –1;

else

return fabs( ( paliwo * 100 ) / dystans );

}

. . .

spalanie = oblicz_spalanie( 40.5, 0 );

if( spalanie == -1 )

cout << "Nie dokonam oblicze dla bł dnych danych";ń ę else

cout << "Spalanie wynosi " << spalanie << " l na 100 km"; . . .

(15)

Definiowanie funkcji — pułapka pierwsza, rezultat typu int

Definiowanie funkcji — pułapka pierwsza, rezultat typu int

W języku C/C++ wolno czasem opuścić słowo kluczowe int, wtedy zostanie ono przyjęte domyślnie. To, że tak robić można nie oznacza, że tak robić trzeba.

int fun( void ) { . . . } fun( void ) { . . . } Zapisy równoważne:

(16)

Definiowanie funkcji — pułapka druga, puste nawiasy parametrów

Definiowanie funkcji — pułapka druga, puste nawiasy parametrów

int fun( void ) { ciało funkcji } int fun() { ciało funkcji } Zapisy równoważne w C++:

(17)

void inc( int i ) { ++i; } . . . int a = 5; inc( a ); cout << a;

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Co wyprowadzi program?

(18)

void inc( int i ) { ++i; } . . . int a = 5; inc( a ); cout << a;

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Jaki jest stan pamięci przed wywołaniem? 5 a Przed wywołaniem inc( a ) 5 a

(19)

void inc( int i ) { ++i; } . . . int a = 5; inc( a ); cout << a;

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Co się dzieje w trakcie wywołania? 5 a Przed wywołaniem inc( a ) 5 a Wywołanie inc( a ) 5 i 5 a

(20)

void inc( int i ) { ++i; } . . . int a = 5; inc( a ); cout << a;

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Co się dzieje w trakcie wykonania? 5 a Przed wywołaniem inc( a ) 5 a Wywołanie inc( a ) 5 i 5 a Wykonanie inc( a ) 6 5X i 5 a

(21)

void inc( int i ) { ++i; } . . . int a = 5; inc( a ); cout << a;

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Jaki jest stan pamięci po wywołaniu? 5 a Przed wywołaniem inc( a ) 5 a Wywołanie inc( a ) 5 i 5 a Wykonanie inc( a ) 6 5X i 5 a a 5 Po wykonaniu inc( a ) 5 a

(22)

Przekazywanie parametrów przez wartość

Przekazywanie parametrów przez wartość

Przy przekazywaniu parametrów przez wartość, wartość parametru aktualnego wywołania funkcji kopiowana jest do parametru formalnego funkcji.

Od tego momentu parametr aktualny i formalny są od siebie niezależne. Żadna modyfikacja parametru formalnego funkcji nie przenosi się na

parametr aktualny wywołania.

(23)

Przekazywanie parametrów przez referencję

Przekazywanie parametrów przez referencję

void inc( int & i )

{ ++i; } . . . int a = 5; inc( a ); cout << a; Co wyprowadzi program?

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

(24)

Przekazywanie parametrów przez referencję

Przekazywanie parametrów przez referencję

void inc( int & i )

{ ++i; } . . . int a = 5; inc( a ); cout << a;

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Jaki jest stan pamięci przed wywołaniem? 5 a Przed wywołaniem inc( a ) 5 a

(25)

Przekazywanie parametrów przez referencję

Przekazywanie parametrów przez referencję

void inc( int & i )

{ ++i; } . . . int a = 5; inc( a ); cout << a;

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

5 a Przed wywołaniem inc( a ) 5 a Co się dzieje w trakcie wywołania? 5 a Wywołanie inc( a ) i

(26)

Przekazywanie parametrów przez referencję

Przekazywanie parametrów przez referencję

void inc( int & i )

{ ++i; } . . . int a = 5; inc( a ); cout << a;

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

5 a Przed wywołaniem inc( a ) 5 a a 5 Wywołanie inc( a ) Co się dzieje w trakcie wykonania? a Wykonanie inc( a ) i i ++i 6 5X

(27)

Przekazywanie parametrów przez referencję

Przekazywanie parametrów przez referencję

void inc( int & i )

{ ++i; } . . . int a = 5; inc( a ); cout << a;

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

Parametr formalny i jest referencją do parametru aktualnego wywołania funkcji

5 a Przed wywołaniem inc( a ) 5 a a 5 Wywołanie inc( a ) a Wykonanie inc( a ) i i ++i 6 5X

Jaki jest stan pamięci po wywołaniu? 5 a 6 a Po wykonaniu inc( a )

(28)

Wykorzystanie parametrów referencyjnych

Wykorzystanie parametrów referencyjnych

Przy przekazywaniu parametrów przez referencję, parametr aktualny wywołania funkcji „nakłada” się na parametr formalny funkcji.

Od tego momentu parametr aktualny i formalny odnoszą się do tej samej lokalizacji (adresu) w pamięci operacyjnej.

Każda modyfikacja parametru formalnego funkcji przenosi się na parametr

aktualny wywołania.

(29)

Funkcja a przekazywanie parametrów przez referencję

Funkcja a przekazywanie parametrów przez referencję

double czytajDystans() {

double liczba;

do {

cout << endl << "Podaj dystans: "; cin >> liczba;

if( liczba <= 0 )

cout << "Dystans musi byc liczba dodatnia"; }

while( liczba <= 0 );

return liczba;

}

Wczytywanie liczby — wykorzystanie funkcji

(30)

Funkcja a przekazywanie parametrów przez referencję

Funkcja a przekazywanie parametrów przez referencję

double czytajDystans( double & liczba ) {

do {

cout << endl << "Podaj dystans: "; cin >> liczba;

if( liczba <= 0 )

cout << "Dystans musi byc liczba dodatnia"; }

while( liczba <= 0 ); }

Wczytywanie liczby — wykorzystanie parametru referencyjnego

double dystans;

(31)

Definicja funkcji po jej wywołaniu

Definicja funkcji po jej wywołaniu

int main() {

double dlugosc_boku, pole;

. . .

pole = oblicz_pole_kwadratu( dlugosc_boku );

. . . }

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; } Wywołanie funkcji Wywołanie funkcji Definicja funkcji Definicja funkcji Czy kompilatorowi się to spodoba?

(32)

Czy kompilatorowi się to spodoba?

Czy kompilatorowi się to spodoba?

int main() {

double dlugosc_boku, pole;

. . .

pole = oblicz_pole_kwadratu( dlugosc_boku );

. . . }

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

Wywołanie funkcji Wywołanie funkcji

Definicja funkcji Definicja funkcji

(33)

Skąd te rozbieżności?

Skąd te rozbieżności?

Definicja funkcji występuje po jej wywołaniu.

Kompilator na etapie wywołania jej jeszcze nie zna.

Czyni w stosunku do niej założenia — że to funkcja, której rezultatem jest

wartość int. To założenie może być słusznie albo nie.

Aby kompilator mógł kontrolować poprawność wywołania funkcji, należy to wywołanie poprzedzić definicją lub deklaracją wywoływanej funkcji.

Aby uniknąć niejednoznaczności, wprowadza się prototypy funkcji.

(34)

Prototypy funkcji

Prototypy funkcji

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

Definicja funkcji:

double oblicz_pole_kwadratu( double bok );

Deklaracja — prototyp — funkcji:

typ_rezultatu nazwa_funkcji( lista_parametrów_formalnych ) {

ciało_funkcji }

Ogólna postać definicji funkcji:

(35)

Wykorzystanie prototypów funkcji — zadeklaruj funkcję potem wołaj

Wykorzystanie prototypów funkcji — zadeklaruj funkcję potem wołaj

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok );

int main() {

double dlugosc_boku;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

cout << "Pole: " << oblicz_pole_kwadratu( dlugosc_boku );

return EXIT_SUCCESS; }

double oblicz_pole_kwadratu( double bok ) {

(36)

Można jednak po „paskalowemu” — zdefiniuj funkcje potem wołaj

Można jednak po „paskalowemu” — zdefiniuj funkcje potem wołaj

#include <iostream> #include <cstdlib> using namespace std;

double oblicz_pole_kwadratu( double bok ) {

return bok * bok; }

int main() {

double dlugosc_boku;

cout << endl << "Obliczam pole kwadratu"; cout << endl << "Podaj dlugosc boku: ";

cin >> dlugosc_boku;

cout << "Pole: " << oblicz_pole_kwadratu( dlugosc_boku );

return EXIT_SUCCESS; }

(37)

Podsumowanie informacji o prototypach

Podsumowanie informacji o prototypach

Starsze implementacje C dopuszczały wywoływanie funkcji wcześniej kompilatorowi nieznanych.

W trakcie kompilowania wywołania nieznanej funkcji przez domniemanie

przyjmowano, że jej rezultatem jest wartość int i nic nie wiadomo na temat jej parametrów. Nie pozwalało to kompilatorowi kontrolować poprawności

wywołania funkcji.

Aby kompilator mógł kontrolować poprawność wywołania funkcji, należy to wywołanie poprzedzić definicją lub deklaracją wywoływanej funkcji.

Deklaracja przyjmuje postać prototypu funkcji.

Deklaracja i definicja funkcji powinna być zgodna. Jeżeli w obrębie jednego pliku wystąpi niezgodność, kompilator zgłosi błąd kompilacji.

(38)

Deklaracje zmiennych a struktura programu — klasa pamięci auto

Deklaracje zmiennych a struktura programu — klasa pamięci auto

void fun( float a ) { int i = 0; char c = 'A'; float f; if( i == 0 ) { float i = 100.0; int k; . . . } }

Przesłanianie identyfikatorów ― w obrębie tego bloku instrukcji if nazwa i oznacza, lokalną w tym bloki, zmienną typu float.

Przesłanianie identyfikatorów ― w obrębie tego bloku instrukcji if nazwa i oznacza, lokalną w tym bloki, zmienną typu float.

Zmienne klasy auto mogą być definiowane na początku każdego bloku w C89, w standardzie C99 i w języku C++ każdym miejscu dozwolonym syntaktyką języka. Zmienne klasy auto pojawiają się wraz z wejściem sterowania do bloku

(39)

Deklaracje zmiennych a struktura programu — klasa pamięci auto

Deklaracje zmiennych a struktura programu — klasa pamięci auto

Zmienne klasy auto:

Nie zachowują swoich wartości pomiędzy swoimi kolejnymi kreacjami.

O ile nie zostaną zainicjalizowane, maja wartości przypadkowe.

void fun( float a ) {

int i = 0; int j;

cout << "a = " << a << " | i = " << i << " | j = " << j << endl; } int main() { fun( 1.0 ); fun( 2.0 ); fun( 3.0 ); return EXIT_SUCCESS; }

(40)

Deklaracje zmiennych a struktura programu — klasa pamięci auto

Deklaracje zmiennych a struktura programu — klasa pamięci auto

Zmienna klasy auto tworzone są automatycznie i lokowane są na stosie.

Stos to element procesu, służący do przechowywania danych chwilowych.

Na stosie lokowane są zmienne auto, w tym argumenty funkcji, oraz adresy

powrotu dla wywoływanych podprogramów.

Stos ma ustalony i ograniczony rozmiar ― należy sprawdzić ustalenia rozmiaru stosu w opcjach kompilatora (lub konsolidatora).

Może się zdarzyć, że stos ma rozmiar rzędu kilku kilobajtów.

Wobec powyższego, niebezpieczna może być poniższa definicja dużej tablicy:

void fun( void ) {

float tab[ 10000 ]; . . .

(41)

Deklaracje zmiennych automatycznych w obrębie instrukcji

Deklaracje zmiennych automatycznych w obrębie instrukcji

W C++ można definiować zmienne w obrębie ograniczonym zasięgiem instrukcji:

for( int i = 10; i > 0; i--) cout << endl << i << "...";

i = 0; // Bł dna odwołanie poza zasi giemę ę

switch( char c = getchar() ) { case 'a': case 'e': case 'i': case 'o': case 'u':

case 'y': cout << "Samogloska " << c; break;

. . . }

(42)

Deklaracje zmiennych a struktura programu — klasa pamięci static

Deklaracje zmiennych a struktura programu — klasa pamięci static

void fun_auto() {

int i = 1;

cout << endl << "Auto " << i++; }

void fun_static() {

static int i = 1;

cout << endl << "Static " << i++; } int main() { fun_auto(); fun_static(); fun_auto(); fun_static(); fun_auto(); fun_static();

(43)

Deklaracje zmiennych a struktura programu — klasa pamięci static

Deklaracje zmiennych a struktura programu — klasa pamięci static

Zmienne statyczne mogą być lokalne w bloku lub zewnętrzne dla wszystkich bloków.

Jeżeli zmienna wewnątrz bloku zostanie zadeklarowana ze specyfikatorem

static, to:

jest raz inicjowana wartością inicjalizatora lub nadawana jest jej

wartość zerowa odpowiednio do typu.

przechowuje wartość po opuszczeniu i ponownym wejściu do bloku.

Statyczne zmienne lokalne stanowią prywatną, nieulotną pamięć danej funkcji czy bloku.

(44)

Deklaracje zmiennych a struktura programu — klasa pamięci static

Deklaracje zmiennych a struktura programu — klasa pamięci static

void funkcja_z_limitem_wywolan( void ) {

static int licznik_wywolan = 0;

if( licznik_wywolan < 10 ) {

licznik_wywolan++;

// Tutaj odpowiednie instrukcje

} else

cout << "Wersja demo -- limit wywolan wyczerpany"; }

Przykład wykorzystania zmiennej statycznej — funkcja z limitem wywołań w obrę-bie pojedynczego wykonania programu:

(45)

Deklaracje zmiennych a struktura programu — klasa pamięci register

Deklaracje zmiennych a struktura programu — klasa pamięci register

Deklaracja zmiennej jako register jest równoważna z deklaracją auto, ale

wskazuje że deklarowany obiekt będzie intensywnie wykorzystywany, i w miarę możliwości będzie umieszczony w rejestrze procesora.

Jeżeli nie jest możliwe umieszczenie zmiennej w rejestrze, pozostaje ona w

pamięci.

Zmienne rejestrowe pozwalają zredukować zajętość pamięci i poprawić

szybkość wykonania operacji takie zmienne wykorzystujących.

Jednak większość współczesnych kompilatorów wykorzystuje optymalizację rejestrową, zatem wiele zmiennych i tak przechowywanych jest w rejestrach, mimo braku jawnej specyfikacji jako register.

register int i;

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

int very_time_critical_fun( register int i ) {

(46)

Deklaracje zmiennych a struktura programu — klasa pamięci extern

Deklaracje zmiennych a struktura programu — klasa pamięci extern

double dystans, paliwo;

void czytaj_dane() { . . . cin >> dystans; . . . cin >> paliwo; } void pisz_wyniki() { if( dystans == 0 )

cout << "Nie policze spalania dla zerowego dystansu" ); else

cout << "Spalanie " << ( paliwo * 100 ) / dystans << "l na 100 km" ; } int main() { . . . czytaj_dane(); pisz_wyniki();

(47)

Deklaracje zmiennych a struktura programu — klasa pamięci extern

Deklaracje zmiennych a struktura programu — klasa pamięci extern

Zmienne zewnętrzne deklarowane są na zewnątrz wszystkich funkcji. Zasięg zmiennej zewnętrznej rozciąga się od miejsca deklaracji do końca pliku.

Zmienne zewnętrzne istnieją stale, nie pojawiają się i nie znikają, zachowują swoje wartości i są dostępne dla wszystkich funkcji programy występujących w zakresie danej zmiennej.

Zmienna zewnętrzna jest raz inicjowana wartością inicjalizatora lub

nadawana jest jej wartość zerowa odpowiednio do typu.

Jeżeli dla zmiennej zewnętrznej użyjemy specyfikacji static, to oznacza to uprywatnienie (ograniczenie dostępu) w obrębie danego pliku źródłowego.

Zmienne zewnętrzne oraz ich właściwe definiowanie i deklarowanie mają istotne znaczenie przy organizacji programów wielomodułowych.

(48)

Definicje zmiennych o ustalonej wartości

Definicje zmiennych o ustalonej wartości

Słowo kluczowe const oznacza modyfikator często używany w C++, dostępny jest również — choć rzadziej używany — w języku C.

Modyfikator const użyty w definicji zmiennej lub parametru oznacza, że wartość takiego elementu nie może być zmieniana po zainicjowaniu.

const int i = 1; ...

i = 5; // Niedozwolone

void print_int( const int & i ) {

cout << i; }

void inc( const int & i ) {

++i; // Nie wolno!

}

(49)

Definicje zmiennych o nieprzewidywalnie zmiennej wartości

Definicje zmiennych o nieprzewidywalnie zmiennej wartości

Słowo kluczowe volatile to modyfikator oznaczający obiekt o wartościach zmieniających się w nieprzewidywalny sposób, inaczej obiekty ulotne.

Obiektami takimi mogą być zmienne odnoszące się do obiektów zewnętrznych w stosunku do programu — zmiennych nałożonych na porty We/Wy,

odnoszących się do obszarów BIOS'a, systemu operacyjnego.

Takie zmienne nie powinny być poddawane optymalizacjom ― szczególnie optymalizacji rejestrowej. Specyfikacja volatile zapobiega wszystkim

potencjalnym optymalizacjom.

volatile unsigned char kbdState = ... ; // Zmienna nało ona na dane BIOSż while( kbdState & LR_SHIFT )

{

if( kbdState & L_SHIFT ) // co tam. . .ś

if( kbdState & R_SHIFT )

Ponieważ zmienna kbdState jest z iteracji while często wykorzystywana, kompilator może

„przenieść” ją do rejestru procesora.

Ponieważ zmienna kbdState jest z iteracji while często wykorzystywana, kompilator może

„przenieść” ją do rejestru procesora.

(50)

Funkcje w osobnym module

Funkcje w osobnym module

Funkcje o podobnym przeznaczeniu mogą być grupowane w moduły. Języki C i C++ nie oferują zdefiniowanej syntaktycznie modularyzacji.

Jednak program może się składać z kompilowanych oddzielnie części — zwanych właśnie modułami — łączonych potem przez konsolidator (wraz z bibliotekami) w plik wykonywalny.

Przyjęta konwencja budowania modułów zakłada oddzielenie części publicznej (nagłówkowej) modułu od części implementacyjnej (realizacyjnej).

Część implementacyjna modułu

Część implementacyjna modułu

Część nagłówkowa modułu

Tutaj deklaracje elementów eksportowanych przez moduł — to moduł udostępnia.

Część nagłówkowa modułu

Tutaj deklaracje elementów eksportowanych przez moduł — to moduł udostępnia.

Plik nagłówkowy, rozszerzenia: .h, .hpp, .hxx

Plik nagłówkowy, rozszerzenia: .h, .hpp, .hxx

Plik realizacyjny, rozszerzenia:

Plik realizacyjny, rozszerzenia:

Moduł

(51)

Część publiczna a cześć implementacyjna

Część publiczna a cześć implementacyjna

Część publiczna modułu zawiera opis elementów dostępnych do użytku w innych

modułach programu.

W językach C i C++ część publiczna modułu to osobny plik — plik nagłówkowy (rozszerzenie h, hpp, hxx).

Plik nagłówkowy jest plikiem tekstowym, udostępniany jest i dystrybuowany w wersji tekstu jawnego.

Część implementacyjna modułu zawiera wszystko to, co potrzebne jest dla

działania elementów udostępnianych przez moduł.

W językach C i C++ część implementacyjna modułu to osobny plik — zwykły plik

programu (rozszerzenie c, cpp, cxx).

Część implementacyjna może być udostępniana i dystrybuowana w postaci źródłowej lub skompilowanej (pliki o, obj, lib).

(52)

Funkcje w osobnym module — przykład

Funkcje w osobnym module — przykład

Załóżmy, że chcemy stworzyć moduł o nawie fun, w którym będą zdefiniowane funkcje obliczające pola i obwody figur płaskich.

Zaczniemy od modułu udostępniającego następujące funkcje:

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

Inne moduły programu będą mogły wykorzystywać funkcje zdefiniowane w module fun.

(53)

Funkcje w osobnym module — koncepcja

Funkcje w osobnym module — koncepcja

int main() {

. . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . . return EXIT_SUCCESS; } int main() { . . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . .

return EXIT_SUCCESS; }

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

return 2 * 3.14 * promien; }

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

return 2 * 3.14 * promien; }

(54)

Funkcje w osobnym module — podział modułu na części

Funkcje w osobnym module — podział modułu na części

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return M_PI * promien * promien; }

double obwod_kola( double promien ) {

return 2 * M_PI * promien; }

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return M_PI * promien * promien; }

double obwod_kola( double promien ) {

return 2 * M_PI * promien; }

Moduł z funkcjami: fun

Definicje funkcji udostępnianych

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

Część publiczna modułu: fun.hpp

(55)

Funkcje w osobnym module — włączanie własnego pliku nagłówkowego

Funkcje w osobnym module — włączanie własnego pliku nagłówkowego

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien );

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien );

#include "fun.hpp"

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

return 2 * 3.14 * promien;

#include "fun.hpp"

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return 3.14 * promien * promien; }

double obwod_kola( double promien ) {

return 2 * 3.14 * promien;

Część publiczna modułu: fun.hpp

Część implementacyjna : fun.cpp

Moduły zwykle włączają własny plik nagłówkowy. W tym akurat przypadku nie jest to konieczne.

Moduły zwykle włączają własny plik nagłówkowy. W tym akurat przypadku nie jest to konieczne.

(56)

Funkcje w osobnym module — włączanie innych plików nagłówkowych

Funkcje w osobnym module — włączanie innych plików nagłówkowych

#include "fun.hpp" #include <cmath>

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return M_PI * promien * promien; }

double obwod_kola( double promien ) {

return 2 * M_PI * promien;

#include "fun.hpp" #include <cmath>

double pole_kwadratu( double bok ) {

return bok * bok; }

double obwod_kwadratu( double bok ) {

return 4 * bok; }

double pole_kola( double promien ) {

return M_PI * promien * promien; }

double obwod_kola( double promien ) {

return 2 * M_PI * promien;

Część implementacyjna : fun.cpp

Włączenie pliku nagłówkowego zawierającego definicję stałej π : M_PI

Włączenie pliku nagłówkowego zawierającego definicję stałej π : M_PI

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien );

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

(57)

Funkcje w osobnym module — włączanie innych plików nagłówkowych

Funkcje w osobnym module — włączanie innych plików nagłówkowych

Próba włączenia pliku wiele razy:

Prototypy funkcji zostaną włączone jeden raz

Prototypy funkcji zostaną włączone jeden raz

#ifndef _fun_hpp_ #define _fun_hpp_

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien ); #endif

#ifndef _fun_hpp_ #define _fun_hpp_

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

#endif

Część publiczna modułu: fun.hpp

#include <iostream> #include <cstdlib> #include "fun.hpp" . . . #include "fun.hpp" . . . #include "fun.hpp" #include <iostream> #include <cstdlib> #include "fun.hpp" . . . #include "fun.hpp" . . . #include "fun.hpp" Dyrektywa umożliwiająca kompilację warunkową Dyrektywa umożliwiająca kompilację warunkową

(58)

Funkcje w osobnym module — wykorzystanie pliku nagłówkowego

Funkcje w osobnym module — wykorzystanie pliku nagłówkowego

#include <iostream> #include <cstdlib> int main()

{

. . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . . return EXIT_SUCCESS; } #include <iostream> #include <cstdlib> int main() { . . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . .

return EXIT_SUCCESS; }

Program główny: main.cpp

Ostrzeżenie lub błąd kompilacji — definicje (prototypy) tych funkcji nie są znane!

Ostrzeżenie lub błąd kompilacji — definicje (prototypy) tych funkcji nie są znane!

#include <iostream> #include <cstdlib> #include "fun.hpp" int main() { . . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . . return EXIT_SUCCESS; } #include <iostream> #include <cstdlib> #include "fun.hpp" int main() { . . .

cout << pole_kwadratu( 10 ) << endl; cout << obwod_kwadratu( 10 ) << endl; cout << pole_kola( 10 ) << endl;

cout << obwod_kola( 10 ) << endl; . . .

return EXIT_SUCCESS; }

Program główny: main.cpp

Po włączeniu pliku nagłówkowego fun.hpp deklaracje tych funkcji są znane kompilatorowi

Po włączeniu pliku nagłówkowego fun.hpp deklaracje tych funkcji są znane kompilatorowi

Program w włączonym plikiem nagłówkowym skompiluje się poprawnie, ale nie

(59)

Kompilator, konsolidator... przypomnienie

Kompilator, konsolidator... przypomnienie

Program źródłowy

Edytor

Środowisko do tworzenia programu źródłowego

Plik (pliki) tekstowe, np.: - Pascal : .pas - C : .c - C++ : .cpp, cxx Analizator s yntaktyczny Generator kodu mas zynowego K o m p i l a t o r Kons olidator (ang. linker) Błędy syntaktyczne (składniowe) Błędy konsolidacji programu Kod maszynowy przed konsolidacją

Plik (pliki) object .:

- Dos, Windows : .obj, .tpu - Unix : .o

Kod wykonywalny Plik wykonywalny : - Dos, Windows : .com, .exe - Unix : .out

Biblioteki standardowe, systemowe, specjalizowane

Środowisko uruchomieniowe

(ang. debuger, profiler)

Testowanie i uruchamianie

Błędy wykonania

(60)

Kompilacja + konsolidacja dla pojedynczego modułu

Kompilacja + konsolidacja dla pojedynczego modułu

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator Konsolidator Wersja źródłowa Wersja źródłowa

Realizacja dyrektyw, w tym #include

Realizacja dyrektyw, w tym #include

Kompilacja, generacja kodu maszynowego

Kompilacja, generacja kodu maszynowego

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Plik tekstowy po rozwinięciu dyrektyw preprocesora

Plik tekstowy po rozwinięciu dyrektyw preprocesora fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek

(61)

Kompilacja + konsolidacja dla programu wielomodułowego — problem

Kompilacja + konsolidacja dla programu wielomodułowego — problem

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator Konsolidator Wersja źródłowa Wersja źródłowa

Realizacja dyrektyw, w tym #include

Realizacja dyrektyw, w tym #include

Kompilacja, generacja kodu maszynowego

Kompilacja, generacja kodu maszynowego

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Plik tekstowy po rozwinięciu dyrektyw preprocesora

Plik tekstowy po rozwinięciu dyrektyw preprocesora fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek

Te etapy przebiegają podobnie do kompilacji programu

(62)

Kompilacja + konsolidacja dla programu wielomodułowego — problem

Kompilacja + konsolidacja dla programu wielomodułowego — problem

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator Konsolidator Wersja źródłowa Wersja źródłowa

Realizacja dyrektyw, w tym #include

Realizacja dyrektyw, w tym #include

Kompilacja, generacja kodu maszynowego

Kompilacja, generacja kodu maszynowego

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Dołączenie kodu z bibliotek

standardowych i innych zewnętrznych

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Kod maszynowy, jeszcze nie gotowy do uruchomienia

Plik tekstowy po rozwinięciu dyrektyw preprocesora

Plik tekstowy po rozwinięciu dyrektyw preprocesora fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek

(63)

Kompilacja rozłączna — koncepcja

Kompilacja rozłączna — koncepcja

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator

Konsolidator Dołączenie kodu z bibliotek

standardowych i modułu fun.cpp

Dołączenie kodu z bibliotek standardowych i modułu fun.cpp

fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek fun.cpp fun.cpp Preprocesor Preprocesor Kompilator Kompilator fun.cpp po preprocesingu fun.cpp po preprocesingu fun.o fun.o Kompilacja programu głównego main.cpp fun.hpp fun.hpp

(64)

Kompilacja rozłączna — koncepcja

Kompilacja rozłączna — koncepcja

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator

Konsolidator Dołączenie kodu z bibliotek

standardowych i modułu fun.cpp

Dołączenie kodu z bibliotek standardowych i modułu fun.cpp

fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek fun.cpp fun.cpp Preprocesor Preprocesor Kompilator Kompilator fun.cpp po preprocesingu fun.cpp po preprocesingu fun.o fun.o fun.hpp fun.hpp Kompilacja modułu fun.cpp

(65)

Kompilacja rozłączna — koncepcja

Kompilacja rozłączna — koncepcja

main.cpp main.cpp Preprocesor Preprocesor Kompilator Kompilator main.cpp po preprocesingu main.cpp po preprocesingu main.o main.o Konsolidator

Konsolidator Dołączenie kodu z bibliotek

standardowych i modułu fun.o

Dołączenie kodu z bibliotek standardowych i modułu fun.o

fun.hpp fun.hpp cstdlib cstdlib iostream iostream Pliki bibliotek Pliki bibliotek fun.cpp fun.cpp Preprocesor Preprocesor Kompilator Kompilator fun.cpp po preprocesingu fun.cpp po preprocesingu fun.o

fun.o Kod maszynowy

funkcji Kod maszynowy funkcji Kod maszynowy programu głównego Kod maszynowy programu głównego fun.hpp fun.hpp

(66)

Kompilacja rozłączna — manualne zarządzanie kompilacją

Kompilacja rozłączna — manualne zarządzanie kompilacją

Wywołanie to spowoduje:

kompilacje programu test.cpp,

wygenerowanie pliku pośredniego test.o (w przypadku braku błędów), połączenie test.o z plikami bibliotek i generacja i wynikowego pliku a.out. Załóżmy, że kompilator dostępny jest poleceniem cc (jak w systemach Unixowych) i zmienne środowiskowe są ustalone.

cc test.cpp

Użycie flagi -o umożliwia określenie nazwy pliku wynikowego (np. uruchom).

cc test.cpp –o uruchom

Użycie flagi -c pozwala na samą kompilację (bez konsolidacji programu).

(67)

Kompilacja rozłączna — manualne zarządzanie kompilacją

Kompilacja rozłączna — manualne zarządzanie kompilacją

Załóżmy, że nasz program składa się z modułów:

main.cpp — program główny z funkcją main, fun.cpp — moduł z definicjami funkcji.

Kompilujemy oddzielnie poszczególne moduły:

cc fun.o main.o –o uruchom

W przypadku modyfikacji pliku fun.cpp wystarczy:

cc -c main.cpp

Powstają pliki pośrednie main.o oraz fun.o. Łączymy je w program wykonywalny o nazwie uruchom:

cc -c fun.cpp

(68)

Kompilacja rozłączna — automatyzacja

Kompilacja rozłączna — automatyzacja

make — program realizujący niezbędne kompilacje w oparciu o reguły

zdefiniowane w pliku sterującym (domyślna nazwa — Makefile):

plik ten opisuje zależności pomiędzy modułami programu oraz określa jaki wywołania powinny zostać wykonane dla każdego z modułów,

program make sprawdza czasy modyfikacji plików źródłowych i docelowych i przeprowadza jedynie niezbędne kompilacje.

Makefile dla omawianego przykładu: uruchom : fun.o main.o

cc fun.o main.o –o uruchom fun.o : fun.cpp fun.hpp

cc -c fun.cpp

main.o : main.cpp fun.hpp cc -c main.cpp

(69)

Kompilacja rozłączna — tworzenie projektów w środowiskach IDE

Kompilacja rozłączna — tworzenie projektów w środowiskach IDE

Większość środowisk programistycznych oferuje możliwość budowania projektów. Projekt określa przynajmniej:

pliki źródłowe i pomocnicze wchodzące w skład programu, lokalizację bibliotek, plików nagłówkowych,

opcje kompilacji, typ kodu wynikowego,

(70)

Kompilacja rozłączna — tworzenie projektów w Code::Blocks

(71)

Kompilacja rozłączna — tworzenie projektów w Dev-C++

(72)

Co może eksportować moduł?

Co może eksportować moduł?

#define KEY_UP 0x48 #define KEY_DOWN 0x50 #define KEY_LEFT 0x4b #define KEY_RIGHT 0x4d

Stałe, jako symbole preprocesora Stałe, jako symbole preprocesora:

enum ctrl_key_codes { KEY_UP = 0x48, KEY_DOWN = 0x50, KEY_LEFT = 0x4b, KEY_RIGHT = 0x4d }; Typy wyliczeniowe:

typedef unsigned char byte; typedef unsigned short int word;

(73)

Co może eksportować moduł? cd... .

Co może eksportować moduł? cd... .

const int MAKS_PREDK_ZABUD = 50; const double MOJE_PI = 3.14;

Definicje zmiennych const:

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

Prototypy funkcji:

Uwaga, jeżeli moduł eksportuje definicje typów czy stałych, zwykle trzeba zabezpieczać plik nagłówkowy przed wielokrotnym włączaniem w tym samym zakresie.

Uwaga, jeżeli moduł eksportuje definicje typów czy stałych, zwykle trzeba zabezpieczać plik nagłówkowy przed wielokrotnym włączaniem w tym samym zakresie.

(74)

Zabezpieczenie przed wielokrotnym włączaniem pliku nagłówkowego

Zabezpieczenie przed wielokrotnym włączaniem pliku nagłówkowego

#ifndef _fun_hpp_ #define _fun_hpp_

const double MOJE_PI = 3.14;

double pole_kwadratu( double bok ); . . .

#endif

#ifndef _fun_hpp_ #define _fun_hpp_

const double MOJE_PI = 3.14;

double pole_kwadratu( double bok ); . . . #endif #include "fun.hpp" . . #include "fun.hpp" . . #include "fun.hpp" #include "fun.hpp" . . #include "fun.hpp" . . #include "fun.hpp"

const double MOJE_PI = 3.14;

double pole_kwadratu( double bok ); . . .

const double MOJE_PI = 3.14;

double pole_kwadratu( double bok ); . . . #include "fun.hpp" . . #include "fun.hpp" . . #include "fun.hpp" #include "fun.hpp" . . #include "fun.hpp" . . #include "fun.hpp"

Dyrektywa kompilacji warunkowej:

(75)

Deklaracja zmiennej — informacja o typie i nazwie zmiennej, nie musi zawierać

informacji o klasie pamięci i wartości incjalizującej.

Definicja zmiennej — to deklaracja zawierająca informacje o klasie pamięci

i wartości inicjalizującej.

Eksport zmiennej zewnętrznej

Eksport zmiennej zewnętrznej

Uwaga, jeżeli moduł ma eksportować zmienną, należy w odpowiedni sposób to opisać.

Uwaga, jeżeli moduł ma eksportować zmienną, należy w odpowiedni sposób to opisać.

Definicja zmiennej występuje raz i rezerwuje pamięć dla zmiennej, zgodna z definicją deklaracja może występować w programie wiele razy, ma charakter informacyjny.

Definicja zmiennej występuje raz i rezerwuje pamięć dla zmiennej, zgodna z definicją deklaracja może występować w programie wiele razy, ma charakter informacyjny.

(76)

Eksport zmiennej zewnętrznej

Eksport zmiennej zewnętrznej

extern int input_data_error;

Plik nagłówkowy zawiera deklarację zmiennej:

int input_data_error;

Plik implementacyjny zawiera definicję zmiennej:

#ifndef _fun_hpp_ #define _fun_hpp_

extern int input_data_error;

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien ); #endif

#ifndef _fun_hpp_ #define _fun_hpp_

extern int input_data_error;

double pole_kwadratu( double bok ); double obwod_kwadratu( double bok ); double pole_kola( double promien ); double obwod_kola( double promien );

#endif

#include "fun.hpp" #include <cmath>

int input_data_error;

double pole_kwadratu( double bok ) {

return bok * bok; }

. . .

#include "fun.hpp" #include <cmath>

int input_data_error;

double pole_kwadratu( double bok ) {

return bok * bok; }

(77)

Każda funkcja i zmienna zewnętrzna jest domyślnie eksportowana

Każda funkcja i zmienna zewnętrzna jest domyślnie eksportowana

Każda funkcja i zmienna zewnętrzna występująca w module może być dostępna dla innych modułów programu. Czasem chcemy jednak ograniczyć dostęp do takich zmiennych i funkcji — uprywatnić je w obrębie modułu.

Każda funkcja i zmienna zewnętrzna występująca w module może być dostępna dla innych modułów programu. Czasem chcemy jednak ograniczyć dostęp do takich zmiennych i funkcji — uprywatnić je w obrębie modułu.

static int private_error_flag;

. . .

static void private_error_handler( void )

{

. . . }

Jeżeli definicja zmiennej zewnętrznej lub funkcji zawiera słowo static, nie są one dostępne dla innych modułów programu:

Nazwy takich zmiennych i funkcji mogą się powtarzać w innych modułach programu.

Cytaty

Powiązane dokumenty

the range of space shrouded by this shadow depends on the shape of the illuminated object, on the direction of light incidence and, to a lesser extent, on the distance from the

Several techniques of building monolithic artistic partitions have been developed, namely screen printing and digital printing, enamelled glass (manual application), lami- nated

in this article the issue of architecture as fun or having fun with architecture will be discussed on the basis of some concrete architectural examples, namely the hundertwasserhaus

SuperK-Gd pre-SN warning system ( from M. Vagins talk at Sendai conference 6-9 March 2019 ) Hyper-Kamiokande project starting construction next year, operating 2027 other low

to shout: 'I don't understand anything! What's all about this black and white thing? We gotta stop racism in any way!! What's this with blacks and whites! I'm gonna make a rule in

Nauczyciel podaje temat i ogólny cel lekcji: „Powtórzycie słowa związane z nauką (odkrycia, wynalazki, przedmioty).. Będziecie wykonywać różne ćwiczenia pod kątem

Ludzie są w szoku i mówią “A ty nie wyglądasz jak taka…?. kobieta, która się tym zajmuje” (…) A jak ona

prime fun tions are ne essarily distin t, and this learly implies the unique.