Programowanie Proceduralne
Transkrypt
Programowanie Proceduralne
Programowanie Proceduralne Programowanie Proceduralne Bożena Woźna-Szcześniak [email protected] Jan Długosz University, Poland Wykład 3 Programowanie Proceduralne Typ zmiennoprzecinkowy Typy zmiennoprzecinkowy float Najmniejszy typ rzeczywisty w C. Dobry do obliczeń z dokładnościa˛ do 6 miejsc po przecinku. Obliczenia przy użyciu tego typu sa˛ szybkie, ale łatwo można uzyskać przepełnienie. Typowa wartość minimalna to 10−38 . Typowa wartość maksymalna to 1038 . double “Średni” typ rzeczywisty w C. Dobry do obliczeń z dokładnościa˛ do 12 miejsc po przecinku. Typowa wartość minimalna to 10−308 . Typowa wartość maksymalna to 10308 . Znacznie wolniejszy w obliczeniach od float, ale za to bardziej precyzyjny. Programowanie Proceduralne Typ zmiennoprzecinkowy Typy zmiennoprzecinkowy long double Najwiekszy ˛ typ rzeczywisty w C. Dobry do obliczeń z dokładnościa˛ do 18 miejsc po przecinku. Typowa wartość minimalna to 10−4000 . Typowa wartość maksymalna to 104000 . Obliczenia sa˛ najwolniejsze, ale najbardziej dokładne. float.h Zbiór nagłówkowy zawierajacy ˛ stałe zwiazane ˛ z typem zmiennoprzecinkowym. Programowanie Proceduralne Typ zmiennoprzecinkowy Typ zmiennoprzecinkowy - float.h 1 2 3 4 5 6 7 8 9 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { p r i n t f ( " f l o a t min=%g , max=%g \ n " , FLT_MIN ,FLT_MAX ) ; p r i n t f ( " double min=%l g , max=%l g \ n " , DBL_MIN ,DBL_MAX ) ; p r i n t f ( " l o n g double min=%Lg , max=%Lg \ n " , LDBL_MIN ,LDBL_MAX ) ; return 0; } float min=1.17549e-38, max=3.40282e+38 double min=2.22507e-308, max=1.79769e+308 long double min=3.3621e-4932, max=1.18973e+4932 Programowanie Proceduralne Typ zmiennoprzecinkowy double Typ zmiennoprzecinkowy - double %lf printf wyświetla liczbe˛ rzeczywista˛ z dokładnościa˛ do 6 miejsc po przecinku. %le printf wyświetla liczbe˛ rzeczywista˛ z dokładnościa˛ do 6 miejsc po przecinku, ale w notacji wykładniczej. Np., 1.200000e − 05 znaczy 1.2 · 10−5 . %lg printf wyświetla liczbe˛ rzeczywista˛ z pominieciem ˛ “zbednych” ˛ zer i w najkrótszej możliwej postaci. Np. Zamiast 0.000012 dostajemy 1.2e-05. %a.blf a (np., a=7) wskazuje szerokość liczby, b (np. b=2) wskazuje precyzje˛ (dokładność po przecinku). %.2le Dokładność do 2 miejsc po przecinku w formacie wykładniczym. %.4lg Dokładność do 4 miejsc po przecinku w “zwiezłym” ˛ formacie. Programowanie Proceduralne Typ zmiennoprzecinkowy double Typ zmiennoprzecinkowy - double - przykład 1 1 2 3 4 5 6 7 8 9 10 11 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { double f = 3.1416 , g = 1 .2 e−5, h = 5000000000.0; p r i n t f ( " f=% l f \ t g=% l f \ t h=% l f \ n " , f , g , h ) ; p r i n t f ( " f=%l e \ t g=%l e \ t h=%l e \ n " , f , g , h ) ; p r i n t f ( " f=%l g \ t g=%l g \ t h=%l g \ n " , f , g , h ) ; p r i n t f ( " f =%7.2 l f \ t g =%.2 l e \ t h =%.4 l g \ n " , f , g , h ) ; return 0; } Programowanie Proceduralne Typ zmiennoprzecinkowy double Typ zmiennoprzecinkowy - double - przykład 1, wykonanie 1 2 3 4 5 6 7 8 9 10 11 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { double f = 3.1416 , g = 1 .2 e−5, h = 5000000000.0; p r i n t f ( " f=% l f \ t g=% l f \ t h=% l f \ n " , f , g , h ) ; p r i n t f ( " f=%l e \ t g=%l e \ t h=%l e \ n " , f , g , h ) ; p r i n t f ( " f=%l g \ t g=%l g \ t h=%l g \ n " , f , g , h ) ; p r i n t f ( " f =%7.2 l f \ t g =%.2 l e \ t h =%.4 l g \ n " , f , g , h ) ; return 0; } f=3.141600 f=3.141600e+00 f=3.1416 f= 3.14 g=0.000012 g=1.200000e-05 g=1.2e-05 g=1.20e-05 h=5000000000.000000 h=5.000000e+09 h=5e+09 h=5e+09 Programowanie Proceduralne Typ zmiennoprzecinkowy float Typ zmiennoprzecinkowy - float - przykład 2 1 2 3 4 5 6 7 8 9 10 11 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { f l o a t f = 3.1416 f , g = 1 .2 e−5f , h = 5000000000.0 f ; p r i n t f ( " f=%f \ t g=%f \ t h=%f \ n " , f , g , h ) ; p r i n t f ( " f=%e \ t g=%e \ t h=%e \ n " , f , g , h ) ; p r i n t f ( " f=%g \ t g=%g \ t h=%g \ n " , f , g , h ) ; p r i n t f ( " f =%7.2 f \ t g =%.2e \ t h =%.4g \ n " , f , g , h ) ; return 0; } Programowanie Proceduralne Typ zmiennoprzecinkowy float Typ zmiennoprzecinkowy - float - przykład 2, wykonanie 1 2 3 4 5 6 7 8 9 10 11 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { f l o a t f = 3.1416 f , g = 1 .2 e−5f , h = 5000000000.0 f ; p r i n t f ( " f=%f \ t g=%f \ t h=%f \ n " , f , g , h ) ; p r i n t f ( " f=%e \ t g=%e \ t h=%e \ n " , f , g , h ) ; p r i n t f ( " f=%g \ t g=%g \ t h=%g \ n " , f , g , h ) ; p r i n t f ( " f =%7.2 f \ t g =%.2e \ t h =%.4g \ n " , f , g , h ) ; return 0; } f=3.141600 f=3.141600e+00 f=3.1416 f= 3.14 g=0.000012 g=1.200000e-05 g=1.2e-05 g=1.20e-05 h=5000000000.000000 h=5.000000e+09 h=5e+09 h=5e+09 Programowanie Proceduralne Typ zmiennoprzecinkowy float Typ zmiennoprzecinkowy - long double - przykład 3, wykonanie 1 2 3 4 5 6 7 8 9 10 11 # include < s t d i o . h> # include < f l o a t . h> i n t main ( void ) { long double f = 3.1416 L , g = 1 .2 e−5L , p r i n t f ( " f=%L f \ t g=%L f \ t h=%L f \ n " , f , g , p r i n t f ( " f=%Le \ t g=%Le \ t h=%Le \ n " , f , g , p r i n t f ( " f=%Lg \ t g=%Lg \ t h=%Lg \ n " , f , g , p r i n t f ( " f =%7.2 L f \ t g =%.2Le \ t h =%.4Lg \ n " return 0; } f=3.141600 f=3.141600e+00 f=3.1416 f= 3.14 h = 5000000000.0L ; h); h); h); , f , g, h); g=0.000012 g=1.200000e-05 g=1.2e-05 g=1.20e-05 h=5000000000.000000 h=5.000000e+09 h=5e+09 h=5e+09 Programowanie Proceduralne Typ wyliczeniowy Typ wiliczeniowy ◮ Typ wyliczeniowy to automatyczny mechnizm służacy ˛ do generowania stałych o konkretnych nazwach. ◮ Przykład: enum dzien { poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela } ◮ W typie wyliczeniowym pierwsza wartość domyślnie jest równa zero (patrz przykład 1). ◮ Każda nastepna ˛ ma wartość wieksz ˛ a˛ o jeden - chyba że zostanie zdefiniowana inaczej (patrz przykłady 2 i 3). ◮ Stałe definiowane przy pomocy enums sa˛ implementowane przez kompilator jako “typy calkowite”. Konkretny typ – int, long, long long – jest dobierany na podstawie wartości stałej. Programowanie Proceduralne Typ wyliczeniowy Typ wiliczeniowy ◮ Typ wyliczeniowy to automatyczny mechnizm służacy ˛ do generowania stałych o konkretnych nazwach. ◮ Przykład: enum dzien { poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela } ◮ W typie wyliczeniowym pierwsza wartość domyślnie jest równa zero (patrz przykład 1). ◮ Każda nastepna ˛ ma wartość wieksz ˛ a˛ o jeden - chyba że zostanie zdefiniowana inaczej (patrz przykłady 2 i 3). ◮ Stałe definiowane przy pomocy enums sa˛ implementowane przez kompilator jako “typy calkowite”. Konkretny typ – int, long, long long – jest dobierany na podstawie wartości stałej. Programowanie Proceduralne Typ wyliczeniowy Typ wiliczeniowy ◮ Typ wyliczeniowy to automatyczny mechnizm służacy ˛ do generowania stałych o konkretnych nazwach. ◮ Przykład: enum dzien { poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela } ◮ W typie wyliczeniowym pierwsza wartość domyślnie jest równa zero (patrz przykład 1). ◮ Każda nastepna ˛ ma wartość wieksz ˛ a˛ o jeden - chyba że zostanie zdefiniowana inaczej (patrz przykłady 2 i 3). ◮ Stałe definiowane przy pomocy enums sa˛ implementowane przez kompilator jako “typy calkowite”. Konkretny typ – int, long, long long – jest dobierany na podstawie wartości stałej. Programowanie Proceduralne Typ wyliczeniowy Typ wiliczeniowy ◮ Typ wyliczeniowy to automatyczny mechnizm służacy ˛ do generowania stałych o konkretnych nazwach. ◮ Przykład: enum dzien { poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela } ◮ W typie wyliczeniowym pierwsza wartość domyślnie jest równa zero (patrz przykład 1). ◮ Każda nastepna ˛ ma wartość wieksz ˛ a˛ o jeden - chyba że zostanie zdefiniowana inaczej (patrz przykłady 2 i 3). ◮ Stałe definiowane przy pomocy enums sa˛ implementowane przez kompilator jako “typy calkowite”. Konkretny typ – int, long, long long – jest dobierany na podstawie wartości stałej. Programowanie Proceduralne Typ wyliczeniowy Typ wiliczeniowy ◮ Typ wyliczeniowy to automatyczny mechnizm służacy ˛ do generowania stałych o konkretnych nazwach. ◮ Przykład: enum dzien { poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela } ◮ W typie wyliczeniowym pierwsza wartość domyślnie jest równa zero (patrz przykład 1). ◮ Każda nastepna ˛ ma wartość wieksz ˛ a˛ o jeden - chyba że zostanie zdefiniowana inaczej (patrz przykłady 2 i 3). ◮ Stałe definiowane przy pomocy enums sa˛ implementowane przez kompilator jako “typy calkowite”. Konkretny typ – int, long, long long – jest dobierany na podstawie wartości stałej. Programowanie Proceduralne Typ wyliczeniowy enum - przykład 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # include < s t d i o . h> enum m i e s i a c { p o n i e d z i a l e k , wtorek , sroda , czwartek , p i a t e k , / / sobota , n i e d z i e l a } ; i n t main ( void ) { enum m i e s i a c d z i s = wtorek ; while ( d z i s != sobota ) { p r i n t f ( " Dzi ś j e s t %d d z i e n t y g o d n i a wiec s i e˛ ucze ! \ n " , d z i s + 1 ) ; d z i s ++; } p r i n t f ( " Dzi ś j e s t %d d z i e n ty g o d n i a , c z y l i sobota " ,++ d z i s ) ; p r i n t f ( " wi ec ˛ mam wolne : ) ! \ n " ) ; p r i n t f ( " J u t r o j e s t %d d z i e n ty g o d n i a , c z y l i n i e d z i e l a " ,++ d z i s ) ; p r i n t f ( " wi ec ˛ mam t e ż wolne : ) ! \ n " ) ; return 0; } Programowanie Proceduralne Typ wyliczeniowy enum - przykład, wykonanie e ucze ! Dziś jest 2 dzien tygodnia wiec si˛ Dziś jest 3 dzien tygodnia wiec si˛ e ucze ! Dziś jest 4 dzien tygodnia wiec si˛ e ucze ! Dziś jest 5 dzien tygodnia wiec si˛ e ucze ! Dziś jest 6 dzien tygodnia czyli sobota wi˛ ec mam wolne :)! Jutro jest 7 dzien tygodnia czyli niedziela wi˛ ec mam też wolne :)! Programowanie Proceduralne Typ wyliczeniowy enum - przykład 2 1 2 3 4 5 6 7 8 9 10 # include < s t d i o . h> enum m i e s i a c { s ty c z e n =1 , l u t y , marzec , kwiecien , maj , czerwiec , l i p i e c , / / s i e r p i e n , wrzesien , p a z d z i e r n i k , l i s t o p a d , g r u d z i e n } ; i n t main ( void ) { p r i n t f ( "%d , %d , %d , " , styczen , l u t y , marzec ) ; p r i n t f ( "%d , %d , %d , " , kwiecien , maj , c z e r w i e c ) ; p r i n t f ( " . . . , %d . \ n " , g r u d z i e n ) ; return 0; } 1, 2, 3, 4, 5, 6,..., 12. Programowanie Proceduralne Typ wyliczeniowy enum - przykład 2 1 2 3 4 5 6 7 8 9 10 # include < s t d i o . h> enum m i e s i a c { s ty c z e n =1 , l u t y , marzec , kwiecien , maj , czerwiec , l i p i e c , / / s i e r p i e n , wrzesien , p a z d z i e r n i k , l i s t o p a d , g r u d z i e n } ; i n t main ( void ) { p r i n t f ( "%d , %d , %d , " , styczen , l u t y , marzec ) ; p r i n t f ( "%d , %d , %d , " , kwiecien , maj , c z e r w i e c ) ; p r i n t f ( " . . . , %d . \ n " , g r u d z i e n ) ; return 0; } 1, 2, 3, 4, 5, 6,..., 12. Programowanie Proceduralne Typ wyliczeniowy enum - przykład 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include < s t d i o . h> enum d i r e c t i o n { n o r t h = 0 , e a s t = 90 , south = 180 , west = 270 } ; i n t main ( void ) { int n; do { p r i n t f ( " Podaj co pokazuje kompas : " ) ; s c a n f ( "%d " ,&n ) ; switch ( n ) { case n o r t h : p r i n t f ( " I d z na Polnoc ! \ n " ) ; break ; case e a s t : p r i n t f ( " I d z na Wschod ! \ n " ) ; break ; case south : p r i n t f ( " I d z na P o l u d n i e ! \ n " ) ; break ; case west : p r i n t f ( " I d z na Zachod ! \ n " ) ; break ; d e f a u l t : p r i n t f ( " Kierunek n i e p r a w i d ł o w y ! ! ! \ n " ) ; break ; } } while ( ! ( ( n== n o r t h ) | | ( n== e a s t ) | | ( n==south ) | | ( n==west ) ) ) ; return 0; } Programowanie Proceduralne Typ wyliczeniowy enum - przykład 3, przykładowe wykonanie Podaj co pokazuje kompas: 2 Kierunek nieprawidłowy !!! Podaj co pokazuje kompas: 4 Kierunek nieprawidłowy !!! Podaj co pokazuje kompas: 90 Idz na Wschod . Programowanie Proceduralne Typ wyliczeniowy typdef i enum ◮ Standardowa definicja typu wyliczeniowego, wymaga użycia słowa kluczowego enum przy definiowaniu zmiennych tego typu, przy przekazywaniu argumentów do funkcji, itd. (patrz przykład 1). ◮ Aby uniknać ˛ tak uciażliwego ˛ stosowania nowo zdefiniowanego typu, można wykorzystać instrukcje˛ typdef ◮ Przykład: typedef enum {poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela} miesiac; miesiac dzis = wtorek; Programowanie Proceduralne Typ wyliczeniowy typdef i enum ◮ Standardowa definicja typu wyliczeniowego, wymaga użycia słowa kluczowego enum przy definiowaniu zmiennych tego typu, przy przekazywaniu argumentów do funkcji, itd. (patrz przykład 1). ◮ Aby uniknać ˛ tak uciażliwego ˛ stosowania nowo zdefiniowanego typu, można wykorzystać instrukcje˛ typdef ◮ Przykład: typedef enum {poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela} miesiac; miesiac dzis = wtorek; Programowanie Proceduralne Typ wyliczeniowy typdef i enum ◮ Standardowa definicja typu wyliczeniowego, wymaga użycia słowa kluczowego enum przy definiowaniu zmiennych tego typu, przy przekazywaniu argumentów do funkcji, itd. (patrz przykład 1). ◮ Aby uniknać ˛ tak uciażliwego ˛ stosowania nowo zdefiniowanego typu, można wykorzystać instrukcje˛ typdef ◮ Przykład: typedef enum {poniedzialek, wtorek, sroda, czwartek, piatek, sobota, niedziela} miesiac; miesiac dzis = wtorek; Programowanie Proceduralne Typ wyliczeniowy typdef i enum - przykład 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # include < s t d i o . h> typedef enum { p o n i e d z i a l e k , wtorek , sroda , czwartek , p i a t e k , / / sobota , n i e d z i e l a } m i e s i a c ; i n t main ( void ) { m i e s i a c d z i s = wtorek ; while ( d z i s != sobota ) { p r i n t f ( " Dzi ś j e s t %d d z i e n t y g o d n i a wiec s i e˛ ucze ! \ n " , d z i s + 1 ) ; d z i s ++; } p r i n t f ( " Dzi ś j e s t %d d z i e n ty g o d n i a , c z y l i sobota " ,++ d z i s ) ; p r i n t f ( " wi ec ˛ mam wolne : ) ! \ n " ) ; p r i n t f ( " J u t r o j e s t %d d z i e n ty g o d n i a , c z y l i n i e d z i e l a " ,++ d z i s ) ; p r i n t f ( " wi ec ˛ mam t e ż wolne : ) ! \ n " ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Preprocessor jest rodzajem nie-interaktywnego edytora, który jest “umieszczony na samym poczatku” ˛ kompilatora. ◮ Dzieki ˛ niemu kompilator nigdy nie widzi kodu napisanego przez programiste, ale kod, który wygenerował preprocessor. ◮ Dyrektywy preprocesora sa˛ zatem instrukcjami dla kompilatora. ◮ Dyrektywy nie sa˛ jednak poleceniami jezyka ˛ C. Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Preprocessor jest rodzajem nie-interaktywnego edytora, który jest “umieszczony na samym poczatku” ˛ kompilatora. ◮ Dzieki ˛ niemu kompilator nigdy nie widzi kodu napisanego przez programiste, ale kod, który wygenerował preprocessor. ◮ Dyrektywy preprocesora sa˛ zatem instrukcjami dla kompilatora. ◮ Dyrektywy nie sa˛ jednak poleceniami jezyka ˛ C. Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Preprocessor jest rodzajem nie-interaktywnego edytora, który jest “umieszczony na samym poczatku” ˛ kompilatora. ◮ Dzieki ˛ niemu kompilator nigdy nie widzi kodu napisanego przez programiste, ale kod, który wygenerował preprocessor. ◮ Dyrektywy preprocesora sa˛ zatem instrukcjami dla kompilatora. ◮ Dyrektywy nie sa˛ jednak poleceniami jezyka ˛ C. Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Preprocessor jest rodzajem nie-interaktywnego edytora, który jest “umieszczony na samym poczatku” ˛ kompilatora. ◮ Dzieki ˛ niemu kompilator nigdy nie widzi kodu napisanego przez programiste, ale kod, który wygenerował preprocessor. ◮ Dyrektywy preprocesora sa˛ zatem instrukcjami dla kompilatora. ◮ Dyrektywy nie sa˛ jednak poleceniami jezyka ˛ C. Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Dyrektywy rozpoczynaja˛ sie˛ od znaku # ◮ Każda dyrektywa musi znajdować sie˛ w oddzielnym wierszu. Dyrektywa #include fizycznie wstawia w miejscu jej wystapienia ˛ kod załaczonego ˛ pliku - kompilator zatem widzi zawartość wymienionego w dyrektywie #include pliku: ◮ ◮ ◮ #include <stdio.h> #include “mybib.c” Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Dyrektywy rozpoczynaja˛ sie˛ od znaku # ◮ Każda dyrektywa musi znajdować sie˛ w oddzielnym wierszu. Dyrektywa #include fizycznie wstawia w miejscu jej wystapienia ˛ kod załaczonego ˛ pliku - kompilator zatem widzi zawartość wymienionego w dyrektywie #include pliku: ◮ ◮ ◮ #include <stdio.h> #include “mybib.c” Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ Dyrektywy rozpoczynaja˛ sie˛ od znaku # ◮ Każda dyrektywa musi znajdować sie˛ w oddzielnym wierszu. Dyrektywa #include fizycznie wstawia w miejscu jej wystapienia ˛ kod załaczonego ˛ pliku - kompilator zatem widzi zawartość wymienionego w dyrektywie #include pliku: ◮ ◮ ◮ #include <stdio.h> #include “mybib.c” Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ ◮ #define nazwa_makra ciag_znaków ˛ - służy do definiowania tzw. makr (w tym makr funkcyjnych albo funkcjo-podobnych). Dyrektywa definiuje identyfikator oraz ciag ˛ znaków, który bedzie ˛ zamiast niego wstawiany we wszystkich jego wystapieniach ˛ w programie. Ciagiem ˛ znaków może być np. stała (liczba, łańcuch) lub instrukcja. Przykład: ◮ ◮ ◮ ◮ #define ROZMIAR 150 #define EPS 3.5E-8 #define KOMUNIKAT “Wystapił ˛ niezidentyfikowany bład” ˛ #undef nazwa_makra - anuluje definicje˛ makra ◮ ◮ ◮ #undef ROZMIAR #undef EPS #undef KOMUNIKAT Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ ◮ #define nazwa_makra ciag_znaków ˛ - służy do definiowania tzw. makr (w tym makr funkcyjnych albo funkcjo-podobnych). Dyrektywa definiuje identyfikator oraz ciag ˛ znaków, który bedzie ˛ zamiast niego wstawiany we wszystkich jego wystapieniach ˛ w programie. Ciagiem ˛ znaków może być np. stała (liczba, łańcuch) lub instrukcja. Przykład: ◮ ◮ ◮ ◮ #define ROZMIAR 150 #define EPS 3.5E-8 #define KOMUNIKAT “Wystapił ˛ niezidentyfikowany bład” ˛ #undef nazwa_makra - anuluje definicje˛ makra ◮ ◮ ◮ #undef ROZMIAR #undef EPS #undef KOMUNIKAT Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Dyrektywy preprocesora ◮ ◮ #define nazwa_makra ciag_znaków ˛ - służy do definiowania tzw. makr (w tym makr funkcyjnych albo funkcjo-podobnych). Dyrektywa definiuje identyfikator oraz ciag ˛ znaków, który bedzie ˛ zamiast niego wstawiany we wszystkich jego wystapieniach ˛ w programie. Ciagiem ˛ znaków może być np. stała (liczba, łańcuch) lub instrukcja. Przykład: ◮ ◮ ◮ ◮ #define ROZMIAR 150 #define EPS 3.5E-8 #define KOMUNIKAT “Wystapił ˛ niezidentyfikowany bład” ˛ #undef nazwa_makra - anuluje definicje˛ makra ◮ ◮ ◮ #undef ROZMIAR #undef EPS #undef KOMUNIKAT Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # include < s t d i o . h> i n t main ( void ) { # d e f i n e EPS 3 .5E−8 double d = EPS ; p r i n t f ( " Wprowadziles l i c z b e : %g <−> %.10 l f \ n " , d , d ) ; # d e f i n e ROZMIAR 150 p r i n t f ( " Rozmiar = %d \ n " , ROZMIAR ) ; # undef ROZMIAR # d e f i n e ROZMIAR 15 p r i n t f ( "Nowy Rozmiar = %d \ n " , ROZMIAR ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład Wprowadziles liczbe: 3.5e-08 <-> 0.0000000350 Rozmiar = 150 Nowy Rozmiar = 15 Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład #define ABS(a) ((a)>=0 ? (a) : (-a)) ◮ Powyższe makro oblicza wartość bezwzgledn ˛ a˛ z liczby przekazanej argumentem a. ◮ W przeciwieństwie do funkcji, np. int abs(int,int);, która mogłaby realizować podobne zadanie, makro ABS akceptuje argumenty dowolnego typu arytmetycznego lub nawet wskaźnikowego. ◮ Wada: może obliczać wartość argumentu a wielokrotnie co powoduje generowanie wiekszego kodu. ◮ Uwaga ! Nawiasy sa˛ niezbedne ˛ do poprawnego obliczania wyrażeń. Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # include < s t d i o . h> # define ABS( a ) ( ( a) >=0 ? ( a ) : (−a ) ) i n t main ( void ) { int a; p r i n t f ( " Podaj l i c z b e˛ c a ł k o w i t a˛ : " ) ; p r i n t f ( "ABS(%d ) = %d \ n " , a , ABS( a ) ) ; s c a n f ( "%d " ,& a ) ; double b ; p r i n t f ( " Podaj l i c z b e˛ r z e c z y w i s t a˛ : " ) ; s c a n f ( "%l f " ,& b ) ; p r i n t f ( "ABS(% l f ) = %l f \ n " , b ,ABS( b ) ) ; p r i n t f ( "ABS(% l f ) = %l f \ n " , a−b , ABS( a−b ) ) ; i n t ∗p=&a ; / / w y j a ś n i e n i e na nastenych wykładach p r i n t f ( "ABS(%d ) = %d \ n " ,∗ p , ABS( ∗ p ) ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład Podaj liczb˛ e całkowita: ˛ -3 ABS(-3) = 3 Podaj liczb˛ e rzeczywista: ˛ 78.2 ABS(78.200000) = 78.200000 ABS(-81.200000) = -75.200000 ABS(-3) = 3 Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # include < s t d i o . h> i n t main ( void ) { # d e f i n e even ( x ) ( x ) % 2 ? 0 : 1 int a; p r i n t f ( " Podaj l i c z b e : " ) ; s c a n f ( "%d " ,& a ) ; i f ( even ( a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " , a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " , a ) ; p r i n t f ( " Rozważmy 2∗a = %d \ n " ,2∗ a ) ; i f ( even (2∗ a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " ,2∗ a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " ,2∗ a ) ; p r i n t f ( " Rozważmy 2+a = %d \ n " ,2+ a ) ; i f ( even (2+ a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " ,2+ a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " ,2+ a ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład Podaj liczbe: 3 3 jest nieparzyste Rozważmy 2*a = 6 6 jest parzyste Rozważmy 2+a = 5 5 jest nieparzyste Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład źle zdefiniowanego makra 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # include < s t d i o . h> i n t main ( void ) { # d e f i n e even ( x ) x % 2 ? 0 : 1 int a; p r i n t f ( " Podaj l i c z b e : " ) ; s c a n f ( "%d " ,& a ) ; i f ( even ( a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " , a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " , a ) ; p r i n t f ( " Rozważmy 2∗a = %d \ n " ,2∗ a ) ; i f ( even (2∗ a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " ,2∗ a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " ,2∗ a ) ; p r i n t f ( " Rozważmy 2+a = %d \ n " ,2+ a ) ; i f ( even (2+ a ) ) p r i n t f ( "%d j e s t p a r z y s t e \ n " ,2+ a ) ; else p r i n t f ( "%d j e s t n i e p a r z y s t e \ n " ,2+ a ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład Podaj liczbe: 3 3 jest nieparzyste Rozważmy 2*a = 6 6 jest parzyste Rozważmy 2+a = 5 5 jest nieparzyste -----------------------Podaj liczbe: 4 4 jest parzyste Rozważmy 2*a = 8 8 jest parzyste Rozważmy 2+a = 6 6 jest nieparzyste Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 # include < s t d i o . h> i n t main ( void ) { # d e f i n e ABSDIFF ( a , b ) ( ( a ) > ( b ) ? ( a) −(b ) : ( b) −(a ) ) int a ,b ; p r i n t f ( " Podaj 1 l i c z b e : " ) ; s c a n f ( "%d " ,&a ) ; p r i n t f ( " Podaj 2 l i c z b e : " ) ; s c a n f ( "%d " ,&b ) ; p r i n t f ( " ABSDIFF(%d,%d ) = %d \ n " , a , b , ABSDIFF ( a , b ) ) ; # undef ABSDIFF # d e f i n e MAX( a , b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) p r i n t f ( "MAX(%d,%d ) = %d \ n " , a , b ,MAX( a , b ) ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład Podaj 1 liczbe: 5 Podaj 2 liczbe: 6 ABSDIFF(5,6) = 1 MAX(5,6) = 6 Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # include < s t d i o . h> # define y 1 # define kwadrat ( a ) ( ( a ) ∗ ( a ) ) # define x 2 # define g kwadrat # define t ( a ) ( a ) i n t main ( void ) { i n t a=y ; / / a=1 i n t b=x ; / / b=2 p r i n t f ( " a=%d , b=%d \ n " , a , b ) ; a = t (a ) ; p r i n t f ( " a= t ( a)=%d , b=%d \ n " , a , b ) ; a = kwadrat ( b ) ; p r i n t f ( " a=kwadrat ( b)=%d , b=%d \ n " , a , b ) ; a = g(b ) ; p r i n t f ( " a=g ( b)=%d , b=%d \ n " , a , b ) ; a = kwadrat ( y + 1 ) ; p r i n t f ( " a = kwadrat ( y+1)=%d , y=%d \ n " , a , y ) ; b = kwadrat ( kwadrat ( x ) ) ; p r i n t f ( " x = %d , b = kwadrat ( kwadrat ( x ))=%d \ n " , x , b ) ; b = t ( t (g (0)) + t ( 1 ) ) ; p r i n t f ( " b = t ( t ( g ( 0 ) ) + t ( 1 ) ) = %d \ n " , b ) ; return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład a=1, b=2 a=t(a)=1, b=2 a=kwadrat(b)=4,b=2 a=g(b)=4, b=2 a = kwadrat(y+1)=4, y=1 x = 2, b = kwadrat(kwadrat(x))=16 b = t(t(g(0)) + t(1)) = 1 Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include < s t d i o . h> i n t main ( void ) { # d e f i n e s t r ( x ) #x char c1 [ ] = s t r ( h e l l o ) ; / / char c1 [ ] = " h e l l o " ; p r i n t f ( "%s \ n " , c1 ) ; # d e f i n e s t r s t r ( x ) #x#x char c2 [ ] = s t r s t r ( h e l l o ) ; p r i n t f ( "%s \ n " , c2 ) ; # d e f i n e s t r s t r s t r ( x ) #x#x#x char c3 [ ] = s t r s t r s t r ( h e l l o ) ; p r i n t f ( "%s \ n " , c3 ) ; return 0; } Jeśli parametr w definicji makra jest bezpośrednio poprzedzony przez znak #, to parametr ten zostaje ujety ˛ w znaki cudzysłowu. Tzn., #parameter zostaje zastapione ˛ przez “parameter”. Nastepnie ˛ każdy cudzysłów jest poprzedzony znakiem \. hello hellohello hellohellohello Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 # include < s t d i o . h> i n t main ( void ) { # d e f i n e t e m p f i l e ( d i r ) # d i r " ma k o ta " p r i n t f ( "%s \ n " , t e m p f i l e ( " Ala " ) ) ; # undef t e m p f i l e # d e f i n e t e m p f i l e ( d i r ) # d i r "%s " p r i n t f ( t e m p f i l e ( / user / i n c l u d e / ) , " s t d d e f . h " ) ; pri ntf ( " \n" ); p r i n t f ( t e m p f i l e ( " / user / i n c l u d e / " ) , " s t d d e f . h " ) ; return 0; } "Ala" ma kota /user/include/stddef.h "/user/include/"stddef.h Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Przykład 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include < s t d i o . h> i n t main ( void ) { # d e f i n e c a t ( x , y ) x##y #define xcat ( x , y ) cat ( x , y ) in t c = cat ( 1 , 2 ) ; p r i n t f ( " \ n%d \ n " , c ∗ 2 ) ; i n t c a t ( B ,WS) = 2011; p r i n t f ( "BWS = %d \ n " ,BWS) ; / / i n t d= c a t ( c a t ( 1 , 2 ) , 3 ) ; − ZLE in t d = xcat ( xcat ( 1 , 2 ) , 3 ) ; p r i n t f ( " d = %d \ n " , d ) ; return 0; } Jeśli definicja makra zawiera wystapienie ˛ operatora ##, to parametry zostaja˛ połaczone ˛ w jeden token, a operator ## usuniety. ˛ Dodatkowo makro przestaje być już rozwijane. 24 BWS = 2011 d = 123 Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - przykład #include<stdio.h> #define scat(x,y) #x #y #define typ(y) scat(%,y) #define END 10 #define FOREACH(TAB,BEGIN, END,format) \ for ( int i = BEGIN; i < (END); ++i)\ { \ if (i % 3==0 ) printf ("\n"); \ printf("[%d] = ",i); \ printf(typ(format),TAB[i]);\ printf(", ");\ } \ printf("\n"); Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - przykład #include<stdio.h> #define scat(x,y) #x #y #define typ(y) scat(%,y) #define END 10 //Podajemy tylko koniec #define PRINTTAB(TAB,END,format) \ for ( int BEGIN = 0; (BEGIN) < (END); ++BEGIN)\ { \ if (BEGIN % 3==0 ) printf ("\n"); \ printf("[%d] = ",BEGIN); \ printf(typ(format),TAB[BEGIN]);\ printf(", ");\ } \ printf("\n"); Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - przykład int main(void) { int a[]={1,2,3}; printf("Tablica a, zakres [0..2]:"); FOREACH(a,0,sizeof(a)/sizeof(a[0]),d); printf("Tablica a, zakres [0..9]:"); PRINTTAB(a,10,d); double b[10]={1.0,22.0,3.3}; printf("Tablica a, zakres [0..9]:"); FOREACH(b,0,10,lf); char c[]="ALA MA Kota"; printf("Tablica c:"); FOREACH(c,0,sizeof(c)/sizeof(c[0]),c); PRINTTAB(c,sizeof(c)/sizeof(c[0]),c); return 0; } Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - przykład Tablica a, zakres [0..2]: [0] = 1, [1] = 2, [2] = 3, Tablica a, zakres [0..9]: [0] = 1, [1] = 2, [2] = 3, [3] = 134513448, [4] = 10910560, [5] = 134520820, [6] = 6, [7] = 3, [8] = 9913124, [9] = 9912308, Tablica a, zakres [0..9]: [0] = 1.000000, [1] = 22.000000, [2] = 3.300000, [3] = 0.000000, [4] = 0.000000, [5] = 0.000000, [6] = 0.000000, [7] = 0.000000, [8] = 0.000000, [9] = 0.000000, Tablica c: [0] = A, [1] = L, [2] = A, [3] = , [4] = M, [5] = A, [6] = , [7] = K, [8] = o, [9] = t, [10] = a, [11] = , [0] [3] [6] [9] = A, [1] = L, [2] = = , [4] = M, [5] = = , [7] = K, [8] = = t, [10] = a, [11] A, A, o, = , Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - kompilacja warunkowa ◮ Dyrektywy kompilacji warunkowej: #if, #else, #elif, #endif ◮ Dyrektywy kompilacji warunkowej pozwalaja˛ wybiórczo kompilować fragmenty kodu źródłowego, pozwalaja˛ na tworzenie różnych wersji programu. ◮ Z uwagi na to, że wartość wyrażenia obliczana jest na etapie kompilacji to elementami wyrażenia w dyrektywie #if moga˛ być jedynie wartości makr oraz stałe. ◮ Ogólna postać dyrektyw #if, #endif: #if wyrażenie_stałe instrukcje #endif Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - kompilacja warunkowa ◮ Ogólna postać dyrektywy #if z #else i #endif: #if wyrażenie_stałe instrukcje1 #else instrukcje2 #endif Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - kompilacja warunkowa ◮ Ogólna postać dyrektywy #if z #elif, #else i #endif: #if wyrażenie_stałe_1 instrukcje_1 #elif wyrażenie_stałe_2 instrukcje_2 ........................ #else instrukcje_n #endif Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - kompilacja warunkowa, wordsize.h /* Determine the wordsize from the preprocessor defines. */ #if defined __x86_64__ # define __WORDSIZE 64 # define __WORDSIZE_COMPAT32 1 #else # define __WORDSIZE 32 #endif Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - test zdefiniowania ◮ #defined identyfikator // 1 : gdy identyfikator był już zdefiniowany // 0 : gdy identyfikator jest nie zdefiniowany #if defined identyfikator /* równoważne */ #ifdef identyfikator ◮ #if ! defined identyfikator /* równoważne */ #ifndef identyfikator Programowanie Proceduralne Dyrektywy preprocesora zdefiniowane w ANSI C Preprocesor - Polecenia dla kompilatora ◮ ◮ # error komunikat_o_błedzie ˛ zleca kompilatorowi zakończenie kompilowania programu w miejscu jej wystapienia ˛ (jest stosowana na etapie usuwania błedów). ˛ #pragma umożliwia przekazanie kompilatorowi dodatkowych instrukcji (zależna od kompilatora): ◮ ◮ ◮ ◮ Wiadomość podczas kompilacji: #pragma message “WersjaProbna”. #pragma exit funkcje - określa funkcje majace ˛ zostać wywoływane tuż przed zakończeniem działania programu. #pragma startup funkcje - określa funkcje majace ˛ zostać wywoływane tuż po rozpoczeciu ˛ działania programu; ...