Podstawy programowania w języku C i C++

Podobne dokumenty
Języki programowania obiektowego Nieobiektowe elementy języka C++

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 12 - sem.iii. M. Czyżak

Co nie powinno być umieszczane w plikach nagłówkowych:

Podstawy programowania w języku C++

Wprowadzenie do programowania w języku C

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Wykład. Materiały bazują częściowo na slajdach Marata Dukhana

Podstawy programowania w języku C i C++

Wykład 15. Literatura. Kompilatory. Elementarne różnice. Preprocesor. Słowa kluczowe

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 3. Karol Tarnowski A-1 p.

Języki programowania. Przetwarzanie plików amorficznych Konwencja języka C. Część siódma. Autorzy Tomasz Xięski Roman Simiński

Podstawy programowania w języku C++

Etapy kompilacji. Wykład 7. Przetwarzanie wstępne, str. 1. #define ILE for(i=0; i<ile; i++)...

Programowanie w języku C++

Funkcja (podprogram) void

Wprowadzenie do programowania w języku C

Podstawy programowania C. dr. Krystyna Łapin

zastępować zarezerwowane słowa lub symbole innymi,

Podstawy programowania w języku C++

Podstawy programowania w języku C++

Język C - podstawowe informacje

1 Podstawy c++ w pigułce.

Podstawy programowania. Wykład 9 Preprocesor i modularna struktura programów. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Laboratorium 3: Preprocesor i funkcje ze zmienną liczbą argumentów. mgr inż. Arkadiusz Chrobot

1 Podstawy c++ w pigułce.

KURS C/C++ WYKŁAD 1. Pierwszy program

Programowanie I C / C++ laboratorium 01 Organizacja zajęć

Wstęp do Programowania, laboratorium 02

2 Przygotował: mgr inż. Maciej Lasota

Podstawy programowania

Poprzedni wykład [ ] :

Preprocesor. natychmiast następuje \n są usuwane następny wiersz zostaje połączony z tym, w którym był znak \ o usuwane są wszystkie komentarze są

#line #endif #ifndef #pragma

Podstawy programowania w języku C++

Programowanie strukturalne i obiektowe

Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR

Wstęp do programowania

Podstawy programowania w języku C++

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania w języku C++

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Język C, tablice i funkcje (laboratorium, EE1-DI)

Podstawy Programowania.

Język C część 1. Sformułuj problem Zanalizuj go znajdź metodę rozwiązania (pomocny może byd algorytm) Napisz program Uruchom i przetestuj czy działa

Programowanie I C / C++ laboratorium 02 Składnia pętli, typy zmiennych, operatory

Język ludzki kod maszynowy

Programowanie Proceduralne

Języki programowania obiektowego Nieobiektowe elementy języka C++

Języki programowania. Tablice struktur, pliki struktur. Część ósma. Autorzy Tomasz Xięski Roman Simiński

Wstęp do programowania INP003203L rok akademicki 2016/17 semestr zimowy. Laboratorium 1. Karol Tarnowski A-1 p.

Wstęp do programowania. Wykład 1

Podstawy programowania w języku C++

Podstawy programowania skrót z wykładów:

Podstawy programowania - 1

Podział programu na moduły

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Ćwiczenie 1. Podstawy. Wprowadzenie do programowania w języku C. Katedra Metrologii AGH

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Typy złożone. Struktury, pola bitowe i unie. Programowanie Proceduralne 1

Wprowadzenie do języka Java

Podstawy Programowania

Język C, tablice i funkcje (laboratorium)

Podstawy Informatyki Wprowadzenie do języka C dr inż. Jarosław Bułat

Wykład VI. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Wykład I. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Zadanie 04 Ktory z ponizszych typow danych w jezyku ANSI C jest typem zmiennoprzecinkowym pojedynczej precyzji?

Wykład 1

PROGRAMOWANIE w C prolog

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

Podstawy programowania. Wykład Pętle. Tablice. Krzysztof Banaś Podstawy programowania 1

Microsoft IT Academy kurs programowania

Abstrakcyjne struktury danych w praktyce

Metodyki i Techniki Programowania MECHANIZM POWSTAWANIA PROGRAMU W JĘZYKU C PODSTAWOWE POJĘCIA

Wstęp do programowania

Programowanie w języku C++

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 2. Karol Tarnowski A-1 p.

Wstęp do Informatyki i Programowania Laboratorium: Lista 0 Środowisko programowania

#include <iostream> using namespace std; void ela(int); int main( ); { Funkcja 3. return 0; }

Wstęp do programowania

Pliki w C/C++ Przykłady na podstawie materiałów dr T. Jeleniewskiego

1. Brian W. Kernighan, Dennis M. Ritchie, Język ANSI C, WNT, Warszawa 1998.

Elementy języka C. ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors.

Informatyka, Ćwiczenie Uruchomienie Microsoft Visual C++ Politechnika Rzeszowska, Wojciech Szydełko. I. ZałoŜenie nowego projektu

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Szablony funkcji i szablony klas

Języki i metodyka programowania. Wprowadzenie do języka C

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Programowanie strukturalne język C - wprowadzenie

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

Na ekranie monitora zostaną wyświetlone w dwu liniach teksty Pierwsza linia Druga linia

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 2. Karol Tarnowski A-1 p.

PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6

Utworzenie pliku. Dowiesz się:

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

Podstawy programowania (1)

Programowanie I. O czym będziemy mówili. Plan wykładu nieco dokładniej. Plan wykładu z lotu ptaka. Podstawy programowania w językach. Uwaga!

Transkrypt:

Podstawy programowania w języku C i C++ Część piąta suplement Funkcje i struktura programu preprocesor Autor Roman Simiński Kontakt roman.siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa. Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne. Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.

Co to jest preprocesor? Preprocesor to zwykle osobny program, realizujący wstępne przetwarzanie kodu źródłowego programu w języku C (C++, Objective C), realizowane przed przekazaniem programu na wejście kompilatora. Zadaniem preprocesora jest wyszukanie w tekście źródłowym programu przeznaczonych dla niego poleceń, oraz ich wykonanie. Wykonanie polecenia oznacza zwykle operację na tekście źródłowym zamianę jednego tekstu na inny, włączenie zawartości jakiegoś innego pliku, pominięcie pewnego fragmentu tekstu itp.. Polecenia dla preprocesora rozpoczynają się znakiem #, np.: #include, #define. Dawniej preprocesor był po prostu programem przetwarzającym dowolny tekst zgodnie z pewnymi dyrektywami. Teraz stosuje się dla języków z grupy C specjalizowane dla tych właśnie języków preprocesory. Copyright Roman Simiński Strona : 2

Działanie preprocesora Wykonanie poleceń Program źródłowy w języku C/C++ Zawiera polecenia dla preprocesora Preprocesor Program źródłowy w języku C/C++ po wykonaniu poleceń preprocesora Kompilator Kod binarny Copyright Roman Simiński Strona : 3

Dyrektywy preprocesora wprowadzenie Język poleceń dla preprocesora składa się z dyrektyw, które są wykonywane oraz makr, które są rozwijane. Pozwalają one na: Włączanie w dane miejsce przetwarzanego pliku, zawartości innego pliku. Zastępowanie symboli i makr ich odpowiednikami. Kompilację warunkową pewne fragmenty programu mogą być kompilowane lub nie. Diagnostykę i kontrolowanie kodu źródłowego. Copyright Roman Simiński Strona : 4

Dyrektywa #include wstawianie zawartości plików Dyrektywa #include wykorzystywana jest zwykle do wstawiania zawartości plików nagłówkowych. Wstawiany tą dyrektywą plik nie musi być wcale plikiem nagłówkowym, preprocesorowi jest właściwie wszystko jedno, co jest wstawiane. Preprocesor wstawia plik w miejscu wystąpienia dyrektywy #include. Dwie postacie dyrektywy wstawiania plików : #include <nazwa pliku> preprocesor poszukuje pliku w katalogach znanych kompilatorowi, zależą one od systemu operacyjnego, samego kompilatora ale również środowiska programistycznego IDE. #include nazwa pliku preprocesor poszukuje pliku katalogu bieżącym, a gdy tam plik nie występuje, przeszukiwane są lokalizacje znane kompilatorowi. Copyright Roman Simiński Strona : 5

Dyrektywa #include przykłady #include <stdio.h> #include <stdlib.h> #include "mojefun.h" int main() { } Przekładowy program test.c zapisanego w katalogu e:\programy\test: Lokalizacje include ustawione w IDE Lokalizacje include właściwe dla kompilatora Katalog bieżący programu Copyright Roman Simiński Strona : 6

Dyrektywa #include umożliwia segmentację programu Segmentacja programu źródłowego to jego podział na części nie stanowiące osobnych jednostek kompilacji. Segmenty programu łączone są w jeden plik przed rozpoczęciem kompilacji. Mimo iż w językach C/C++ segmentacja programu stosowana jest rzadko, można ją zrealizować posługując się preprocesorem. Segmenty programu #include <stdio.h> #include <stdlib.h> inc.c double p_k( double bok ) { return bok * bok; } fun.c int main() { pole = p_k( num ); } main.c #include "inc.c" #include "fun.c" #include "main.c" Preprocesor program.c #include <stdio.h> #include <stdlib.h> double p_k( double bok ) { return bok * bok; } int main() { pole = p_k( num ); } Copyright Roman Simiński Strona : 7

Dyrektywa #include ciekawostki #include <stdlib.h> #include <stdio.h> int main() { puts( #include "hello.txt" ); return EXIT_SUCCESS; } Copyright Roman Simiński Strona : 8

Dyrektywa #include ciekawostki #include <stdlib.h> #include <stdio.h> char hello[] = #include "hello.txt" ; int main() { puts( hello ); return EXIT_SUCCESS; } Copyright Roman Simiński Strona : 9

Dyrektywa #define stałe symboliczne Dyrektywa #define oznacza makrodefinicję. Makrodefinicja definiuje symbol oraz odpowiadający mu ciąg znaków, rozciągający się do znaku końca linii. Preprocesor zastępuje zdefiniowany symbol odpowiadającym mu ciągiem znaków. W makrodefinicji mogą występować parametry. W najprostszej postaci, dyrektywa #include wykorzystywana jest do definiowania stałych symbolicznych: #define PI 3.14 #define DWA_PI 2*PI #define LB_MIESIECY 12 #define POLROCZE LB_MIESIECY/2 pole_kola = PI * r * r; obwod_kola = DWA_PI * r; for( i = 0; i < LB_MIESIECY; i++ ) pole_kola = 3.14 * r * r; obwod_kola = 2*3.14 * r; for( i = 0; i < 12; i++ ) Copyright Roman Simiński Strona : 10

Dyrektywa #define uwaga na średnik Preprocesor zastępuje zdefiniowany symbol odpowiadającym mu ciągiem znaków aż do znacznika końca linii. Użycie średnika na końcu linii może spowodować problem. Uwaga IDE zwykle pokazuje kod źródłowy przed preprocesingiem, komunikaty kompilator mogą wydać się dziwne. Programista widzi kod źródłowy Kompilator widzi kod po preprocesingu pole_kola = 3.14; * r * r; Niewłaściwy argument operatora * Copyright Roman Simiński Strona : 11

Dyrektywa #define stałe symboliczne, cd.... Dyrektywa #definie to nie tylko stałe numeryczne: #define HELLO_PL "Czesc!" #define HELLO_EN "Hello!" #define UWAGA puts( "Uwaga!" ); #define UWAGA_PL_EN puts( "Uwaga!" ); puts( "Warning!" ); printf( HELLO_PL ); UWAGA UWAGA_PL_EN printf( "Czesc!" ); puts( "Uwaga!" ); puts( "Uwaga!" ); puts( "Warning!" ); Dyrektywy mogą być dłuższe niż jeden wiersz: #define POWITANIE "Czesc! Witaj w programie, możesz byc pew\ ny, ze postarczy ci on wielu milych doznan" #define HELLO_PL_EN puts( "Czesc!" ); \ puts( "Hello!" ); Kontynuacja dyrektywy w następnym wierszu Copyright Roman Simiński Strona : 12

Dyrektywa #define makrodefinicje z parametrami Dyrektywa #definie może definiować makra z parametrami, przypominające swą postacią funkcje: #define DO_KWADRATU(X) ((X)*(X)) #define SREDNIA(X,Y) (((X)+(Y))/2) Argumenty makra są zastępowane w trakcie jego rozwijania: float wynik, a, b; wynik = DO_KWADRATU(3); a = 1; b = 4; wynik = SREDNIA(a,b); float wynik, a, b; wynik = ((3)*(3)); a = 1; b = 4; wynik = (((a)+(b))/2); Copyright Roman Simiński Strona : 13

Dyrektywa #define makrodefinicje z parametrami, cd.... Po co w tych makrach tyle nawiasów? Zobaczmy co by było, gdyby ich nie było: #define DO_KWADRATU(X) X*X Wykorzystajmy makro z parametrami, będącymi wyrażeniami: float wynik; wynik = DO_KWADRATU(3+2); float wynik; wynik = 3+2*3+2; (3+2) 2 = 25 11 #define DO_KWADRATU(X) (X)*(X) wynik = (3+2)*(3+2); Copyright Roman Simiński Strona : 14

Dyrektywa #define makrodefinicje z parametrami, cd.... Czy to makro jest już rzeczywiście dobre? #define DO_KWADRATU(X) (X)*(X) Zobaczmy: float wynik; wynik = 100/DO_KWADRATU(2); float wynik; wynik = 100/(2)*(2); 100/2 2 = 100/4=25 (100/2)*2 = 50*2=100 #define DO_KWADRATU(X) ((X)*(X)) wynik = 100/((2)*(2)); Copyright Roman Simiński Strona : 15

Dyrektywa #define makrodefinicje z parametrami, cd.... W makrach zwykle stosujemy nawiasy wokół parametrów o charakterze numerycznym. Jednak cześć problemów z makrami jest niemożliwa do rozwiązania: #define DO_KWADRATU(X) ((X)*(X)) float wynik, a = 2; wynik = DO_KWADRATU(++a); float wynik, a = 2; wynik = ((++a)*(++a)); (++a) 2 = 9 12 albo i jeszcze inaczej... Ponieważ pewnych problemów z makrami nie można uniknąć, programiści zwyczajowo piszą nazwy makr dużymi literami wtedy wiemy, że używamy makra. Copyright Roman Simiński Strona : 16

Dyrektywa #define makrodefinicje vs funkcje Makra mogą zastąpić funkcje są szybsze bo rozwinięte makro nie zawiera kodu zarządzającego wywołaniem funkcji. Makro powinno być krótkie, bo każde użycie makra powoduje jego rozwinięcie w miejscu wykorzystania. W wielu bibliotekach coś co wygląda na funkcje, w rzeczywistości jest makrem, często nazwy makr nie są pisane dużymi literami, np.: #define ferror(f) #define feof(f) ((f)->flags & _F_ERR) ((f)->flags & _F_EOF) #define getc(f) \ ((--((f)->level) >= 0)? (unsigned char)(*(f)->curp++) : \ _fgetc (f)) #define putc(c,f) \ ((++((f)->level) < 0)? (unsigned char)(*(f)->curp++=(c)) : \ _fputc ((c),f)) #define getchar() getc(stdin) #define putchar(c) putc((c), stdout) Tego używaliśmy wiele razy jako funkcji..., a to jest makro! Copyright Roman Simiński Strona : 17

Dyrektywa #define makrodefinicje vs funkcje Podnoszenie do kwadratu jako funkcja: double do_kwadratu( double x ) { return x * x; } float wynik, a = 2; wynik = do_kwadratu( ++a ); /* OK! */ W funkcjach nie występują omówione problemy z parametrami, jednak właśnie opracowanie parametrów dla funkcji, jej wywołanie oraz powrót trwają czasem ten niewielki pozornie czas może być istotny. Copyright Roman Simiński Strona : 18

Funkcje wplatane inline jako alternatywa dla makr W języku C++ oraz C99 wprowadzono funkcje wplatane, które są sygnałem dla kompilatora, że jeżeli to możliwe, kod tej funkcji należy rozwinąć w miejscu wywołania. inline double do_kwadratu( double x ) { return x * x; } float wynik, a = 2; wynik = do_kwadratu( ++a ); /* Tutaj cialo funkcji zostanie rozwiniete */ Być może kompilator rozwinie funkcję do_kwadratu w następujący sposób: double tmp = ++a; wynik = temp * temp; /* Mozliwa postac rozwiniecia funkcji do_kwadratu */ W językach C++ i C99 zaleca się stosowanie funkcji wplatanych zamiast makr. Jednak nie każda funkcja może być przez kompilator rozwinięta istnieją pewne ograniczenia. Zatem mimo użycia inline, może się zdarzyć, że kompilator wywoła funkcję w zwykły sposób. Copyright Roman Simiński Strona : 19

Dyrektywa #define przykłady makrodefinicji Krótkie makra ogólnego przeznaczenia: #define MAX(X,Y) ((X) > (Y)? (X) : (Y)) #define ABS(X) ((X) < 0? -(X) : (X)) #define MAX3(X,Y,Z) (MAX( MAX((X), (Y)), (Z) )) Przykładowe makra obsługi kolorów RGB i CMYK: typedef unsigned char BYTE; typedef unsigned short int WORD; typedef unsigned long int DWORD; #define RGB(r,g,b) ((DWORD)((BYTE)(r) ((BYTE)(g) << 8) ((BYTE)(b) << 16))) #define GET_R(color) ((BYTE)(color)) #define GET_G(color) ((BYTE)(((WORD)(color))>>8)) #define GET_B(color) ((BYTE)((color)>>16)) #define CMYK(c,m,y,k) ((DWORD)((BYTE)(k) ((BYTE)(y)<<8) ((BYTE)(m)<<16) \ ((BYTE)(c)<<24))) #define GET_C(cmyk) ((BYTE)(cmyk)) #define GET_M(cmyk) ((BYTE)((cmyk)>> 8)) #define GET_Y(cmyk) ((BYTE)((cmyk)>>16)) #define GET_K(cmyk) ((BYTE)((cmyk)>>24)) Copyright Roman Simiński Strona : 20

Dyrektywa #define przykłady makrodefinicji Makra mogą być rozbudowane: #define SWAP(X,Y) { \ double tmp; \ tmp=x; \ X=Y; \ Y=tmp; \ } int a = 5, b = 10; float c = 5.5, d = 10.5; SWAP( a, b ); SWAP( c, d ); Dzięki standardowym przekształceniom typów obowiązującym w C/C++ to makro będzie działać dla większości typów numerycznych. Jednak mieszając mocno różne typy X i Y należy się spodziewać dziwnych rezultatów. Copyright Roman Simiński Strona : 21

Dyrektywa #define przykłady makrodefinicji, cd.... Ze złożonymi makrami bywają niespodziewane problemy: #define SWAP(X,Y) { \ double tmp; \ tmp=x; \ X=Y; \ Y=tmp; \ } if( a > b ) SWAP( a, b ); else puts( "a <=b" ); if( a > b ) { double tmp; tmp=a; a=b; b=tmp; }; else puts( "a <=b" ); Błąd kompilacji po rozwinięciu makra blok + instrukcja pusta Copyright Roman Simiński Strona : 22

Dyrektywa #define przykłady makrodefinicji, cd.... Takie makro trzeba napisać w wykorzystaniem sztuczki: #define SWAP(X,Y) do{ \ double tmp; \ tmp=x; \ X=Y; \ Y=tmp; \ } while(0) if( a > b ) SWAP( a, b ); else puts( "a <=b" ); if( a > b ) do{ double tmp; tmp=a; a=b; b=tmp; } while(0); else puts( "a <=b" ); Teraz makro rozwija się w jedną instrukcję Copyright Roman Simiński Strona : 23

Dyrektywa #define jeżeli komuś brakuje Pascala... ;) Można w C programować i tak: INTEGER I = 10; REPEAT WRITELN( I ); DEC( I ); UNTIL( I == 0 ); Jeżeli zdefiniujemy takie makra: #define REPEAT do{ #define UNTIL(W) }while(!(w)) #define WRITELN(X) printf( "%d\n", X ) #define DEC(X) #define INTEGER X-- int Otrzymamy do kompilacji: int I = 10; do{ printf( "%d\n", I ); I--; }while(!(i == 0)); Copyright Roman Simiński Strona : 24

Kompilacja warunkowa #ifdef-#else- Dyrektywa #ifdef powoduje wykonanie wszystkich dyrektyw i skompilowanie kodu zawartego aż do lub #else, jeżeli symbol zapisany za #ifdef został zdefiniowany: #ifdef S Tekst kompilowany warunkowo gdy zdefiniowano symbol lub makro S #ifdef S Tekst kompilowany warunkowo gdy zdefiniowano symbol lub makro S #else Tekst kompilowany warunkowo gdy nie zdefiniowano symbolu lub makra S Copyright Roman Simiński Strona : 25

Kompilacja warunkowa #ifdef-#else- przykłady { #ifdef WERSJA_DEMO puts( "Pamietaj o zarejestrowaniu wersji demo!" ); puts( "Podaj identyfikator:" ); Jeżeli gdzieś wcześniej zdefiniowano: #define WERSJA_DEMO To program będzie miał postać: { puts( "Pamietaj o zarejestrowaniu wersji demo!" ); puts( "Podaj identyfikator:" ); Jeżeli nie zdefiniowano symbolu WERSJA_DEMO: { puts( "Podaj identyfikator:" ); Copyright Roman Simiński Strona : 26

Kompilacja warunkowa #ifdef-#else- przykłady #ifdef PISZ_PO_POLSKU puts( "Podaj identyfikator:" ); #else puts( "Enter login" ); void wczytywanie_danych( void ) { #ifdef DIAGNOSTYKA puts( "Rozpoczete wczytywanie danych" ); } puts( "Podaj..." ); Copyright Roman Simiński Strona : 27

Kompilacja warunkowa #ifndef-#else- przykłady Dyrektywa #ifndef bywa najczęściej wykorzystywana do sprawdzenia, czy potrzebny symbol lub makro zostały zdefiniowane: #ifndef PI #define PI 3.14 #ifndef TRUE #define TRUE (0==0) #ifndef FALSE #define FALSE (!TRUE) Starsze preprocesory wymagały, aby znak # występował w pierwszej kolumnie wiersza: #ifndef PI # define PI 3.14 void wczytywanie_danych( void ) { # ifdef DIAGNOSTYKA puts( "Rozpoczete wczytywanie" ); # endif Copyright Roman Simiński Strona : 28

Kompilacja warunkowa #ifndef-#else- Dyrektywa #ifndef wykorzystywana jest zwykle do realizacji zabezpieczenia przed wielokrotnym włączeniem tego samego pliku nagłówkowego do danej jednostki kompilacji: #ifndef _MOJEFUN_H_ #define _MOJEFUN_H_ void przywitanie(); void pozegnanie(); #include "mojefun.h" void przywitanie(); void pozegnanie(); #include "mojefun.h" #include "mojefun.h" Copyright Roman Simiński Strona : 29

Przy okazji poprawny nagłówek dla funkcji z biblioteki C #ifndef _MOJEFUN_H_ #define _MOJEFUN_H_ #ifdef cplusplus extern "C" { void przywitanie(); void pozegnanie(); #ifdef cplusplus } Copyright Roman Simiński Strona : 30

Kompilacja warunkowa wykorzystanie operatora defined Z dyrektywami kompilacji warunkowej może być wykorzystany operator defined jeżeli symbol lub makro S jest zdefiniowany, wartość wyrażenia defined( S )ma wartość 1, w przeciwnym wypadku 0. Bywa to wygodne w wyrażeniach testujących wiele warunków: #if defined( WINDOWS ) defined( DOS ) Cos dla Windows lub DOS'a Dyrektywa #if z operatorem defined oraz dyrektywy #ifdef i #ifndef mogą być stosowane zamiennie: #ifdef WINDOWS #if defined( WINDOWS ) #ifndef WINDOWS #if!defined( WINDOWS ) Copyright Roman Simiński Strona : 31

W dyrektywie #if można testować wartość symboli #if GNUC >= 3 Cos dla kompilatora w wersji 3 i wyzszej #if (_WIN32_WINNT >= 0x0400) #include <winsock2.h> #else #include <winsock.h> Dyrektywa z warunkiem: #if defined( MOJA_BIBLIOTEKA ) && ( MOJA_BIBLIOTEKA < 4 ) Cos dla bibliotek w wersji nizszej ni ż 4 Może być zapisana prościej, bo porównanie z symbolem niezdefiniowanym daje 0: #if MOJA_BIBLIOTEKA < 4 Cos dla bibliotek w wersji nizszej ni ż 4 Copyright Roman Simiński Strona : 32

Preprocesor wykorzystuje dyrektywę #elif Zamiast składać wielokrotnie #if-#else: #if MOJA_BIBLIOTEKA == 1 Cos dla biblioteki w wersji 1 #else / #if MOJA_BIBLIOTEKA == 2 Cos dla biblioteki w wersji 1 #else Cos dla biblioteki w innej wersji ni ż 1 i 2 Można wykorzystać dyrektywę #elif #if MOJA_BIBLIOTEKA == 1 Cos dla biblioteki w wersji 1 #elif MOJA_BIBLIOTEKA == 2 Cos dla biblioteki w wersji 1 #else Cos dla biblioteki w innej wersji ni ż 1 i 2 Copyright Roman Simiński Strona : 33

Dyrektywy #error i #warning Dyrektywa #error przerywa kompilacje programu ze zgłoszeniem błędu o treści zapisanej za dyrektywą: #ifdef WINDOWS_OS #error "Ten program nie bedzie dzialal w srodowisku Windows." Dyrektywa #warning powoduje zgłoszenie ostrzeżenia ale nie przerywa kompilacji programu: #ifdef WINDOWS_OS #warning "Uklad bajtow w slowie odwrotny ni ż w srodowisku Windows." Copyright Roman Simiński Strona : 34

Predefiniowane makra Makro DATE FILE LINE STDC STDC_HOSTED TIME Rezultat makrorozwinięcia Literał łańcuchowy zawierający datę pracy preprocesora, format "MM DD YYYY". Literał łańcuchowy zawierający nazwę bieżącego pliku źródłowego. Literał całkowitoliczbowy, zawierający numer bieżącej linii w przetwarzanym pliku źródłowym. Wartość 1 oznacza, że dana implementacja jest zgodna ze standardem ANSI C. Wartość 1 oznacza, że dana implementacja jest w pełni zgodna ze standardem ANSI C, 0 w przeciwnym wypadku. Literał łańcuchowy zawierający czas, w którym preprocesor przetwarzał dane miejsce kodu źródłowego, format "HH:MM:SS". Istnieją jeszcze inne predefiniowane makra standardowe oraz specyficzne dla środowiska i kompilatora. Copyright Roman Simiński Strona : 35

Predefiniowane makra przykłady zastosowań Wyświetl komunikat diagnostyczny: if( dystans < 0 ) printf( "Blad: ujemny dystans w pliku %s, linia %d.", FILE, LINE ); Wyświetl informacje o pracy preprocesora: printf( "\ninformacje o pracy preprocesora" ); printf( "\nplik zrodlowy: %s", FILE ); printf( "\ndata: %s", DATE ); printf( "\nczas: %s", TIME ); printf( "\nstandard C: %s", ( STDC )? "tak" : "nie" ); printf( "\nnr tej linii: %d", LINE ); Copyright Roman Simiński Strona : 36

Inne możliwości Predefiniowane makra: STDC_VERSION, func, cplusplus. Budowanie i łączenie napisów z wykorzystaniem operatorów #, ##. Pragmy i inne dyrektywy. Oraz. Zobacz: dokumentacja preprocesora kompilatora gcc: http://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_toc.html#sec_contents Copyright Roman Simiński Strona : 37