ISO/ANSI C obsługa błędów ISO/ANSI C. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów

Podobne dokumenty
ISO/ANSI C - biblioteki ISO/ANSI C. ISO/ANSI C - biblioteki. ISO/ANSI C - biblioteki. ISO/ANSI C - biblioteki. ISO/ANSI C - biblioteki

ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów. ISO/ANSI C obsługa błędów

ISO/ANSI C zm. dynamiczne. ISO/ANSI C zm. dynamiczne. ISO/ANSI C zm. dynamiczne. ISO/ANSI C zm. dynamiczne. ISO/ANSI C zm.

ISO/ANSI C zakończenie. ISO/ANSI C zakończenie. ISO/ANSI C zakończenie. ISO/ANSI C zakończenie. ISO/ANSI C zakończenie

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

ISO/ANSI C dostęp do plików ISO/ANSI C. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików

Biblioteka standardowa - operacje wejścia/wyjścia

ISO/ANSI C dostęp do plików ISO/ANSI C. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików

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

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

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

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

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

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

Podział programu na moduły

Wstęp do Programowania, laboratorium 02

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Pobieranie argumentów wiersza polecenia

1 Podstawy c++ w pigułce.

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

Funkcje zawarte w bibliotece < io.h >

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

I - Microsoft Visual Studio C++

Funkcje zawarte w bibliotece < io.h >

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

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

ISO/ANSI C dostęp do plików ISO/ANSI C. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików. ISO/ANSI C dostęp do plików

Podstawy programowania w języku C++

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

Skrypty i funkcje Zapisywane są w m-plikach Wywoływane są przez nazwę m-pliku, w którym są zapisane (bez rozszerzenia) M-pliki mogą zawierać

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

Łącza nienazwane(potoki) Łącza nienazwane mogą być używane tylko pomiędzy procesami ze sobą powiązanymi.

INFORMATYKA Studia Niestacjonarne Elektrotechnika

Programowanie proceduralne INP001210WL rok akademicki 2018/19 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

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

Zmienne, stałe i operatory

Część 4 życie programu

4. Wyrzuć wyjątek jeśli zmienna ist nie istnieje bloki: try, catch i wyrzucanie wyjątku

Wskaźniki do funkcji. Wykład 11. Podstawy programowania ( język C ) Wskaźniki do funkcji (1) Wskaźniki do funkcji (2)

Języki C i C++ Wykład: 2. Wstęp Instrukcje sterujące. dr Artur Bartoszewski - Języki C i C++, sem. 1I- WYKŁAD

Ćwiczenie 4. Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1.

Argumenty wywołania programu, operacje na plikach

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

Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1. Kraków 2013

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

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Programowanie strukturalne i obiektowe

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

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

1 Podstawy c++ w pigułce.

PMiK Programowanie Mikrokontrolera 8051

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

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

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

Obsługa wyjątków. Język C++ WW12

Podstawy programowania komputerów

Programowanie - wykład 4

Wykład 4: Klasy i Metody

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Struktury. Przykład W8_1

Pliki. Informacje ogólne. Obsługa plików w języku C

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 7 maja K.Grzelak (Wykład 8) Programowanie w C++ 1 / 31

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

Tablice, funkcje - wprowadzenie

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Funkcja (podprogram) void

Programowanie w C++ Wykład 6. Katarzyna Grzelak. kwiecień K.Grzelak (Wykład 6) Programowanie w C++ 1 / 40

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

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

2 Przygotował: mgr inż. Maciej Lasota

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

Język ANSI C. część 11. Jarosław Gramacki Instytut Informatyki i Elektroniki

TEMAT : KLASY DZIEDZICZENIE

Pliki. Informacje ogólne. Obsługa plików w języku C

Podstawy programowania C. dr. Krystyna Łapin

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

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

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

Podstawy programowania. Wykład: 5. Instrukcje sterujące c.d. Stałe, Typy zmiennych c.d. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

3. Instrukcje warunkowe

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

Programowanie w języku C++

Język ludzki kod maszynowy

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Język C zajęcia nr 11. Funkcje

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

Podstawy Informatyki. Inżynieria Ciepła, I rok. Wykład 10 Kurs C++

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Program wykonujący operację na plikach powinien zachować schemat działania zapewniający poprawną pracę:

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

Ćwiczenie nr 6. Poprawne deklaracje takich zmiennych tekstowych mogą wyglądać tak:

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Wstęp do programowania

INFORMATYKA Studia Niestacjonarne Elektrotechnika

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

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

Zasady programowania Dokumentacja

Transkrypt:

Poprawa obsługi błędów to jedna z najpewniejszych metod tworzenia solidnie działającego kodu ISO/ANSI C Obsługa błedów Źródła błędów w działających programach: Sytuacje niezgodne z oczekiwaniami autora programu, ale potencjalnie możliwe do wystąpienia Przyczyna: fałszywe oczekiwania autora programu wynikające z lenistwa, albo z wishful thinking czyli pobożnych życzeń autora, że wszystkie warunki prawidłowej pracy zostaną spełnione przez użytkownika, zanim uruchomi on program, albo.. 152 Obsługa błędów w C polega na kontrolowaniu rezultatów wykonania wywoływanych funkcji i powiązaniu z tymi rezultatami kodu obsługującego błąd. Otwieranie pliku (może się udać, lub nie). FILE* stream; char s[100]; stream = fopen( nazwa_pliku, "r" )); fscanf(stream, %s, s); Czy ten kod jest bezpieczny? FILE* stream; char s[100], file_name[100]; stream = fopen( nazwa_pliku, "r" )); if (stream == NULL) /* sprawdzamy, czy otwieranie się powiodło */... Co powinno się znaleźć w miejscu kropeczek? 1. Przerwanie pracy całego programu 2. Wyświetlenie komunikatu o problemie i powrót sterowania do początku działania programu 3. Powrót sterowania do miejsca w którym pobierana jest nazwa pliku 153 154 Podstawowa strategia obsługi błędów polega na sprawdzaniu wartości zwracanej przez funkcję biblioteczną, której wywołaniu mogło towarzyszyć pojawienie się błędu Jeżeli informacje zwracane przez funkcję biblioteczną są zbyt proste, dodatkowo wykorzystywana jest zmienna globalna przechowująca kod błędu: errno Zmienna errno ma ustawiany kod błędu w momencie wywołania żądania systemowego, takiego jak np. próba otwarcia pliku. Należy ja od razu odczytać, bo następne wywołanie może spowodować kolejną zmianę jej wartości. Mając kod błędu możemy zażądać tekstu odpowiadającego temu kodowi i w ten sposób dowiedzieć się czegoś więcej 155 Constant System error message Value E2BIG Argument list too long 7 EACCES Permission denied 13 EAGAIN No more processes or not enough memory or maximum nesting level 11 reached EBADF Bad file number 9 ECHILD No spawned processes 10 EDEADLOCK Resource deadlock would occur 36 EDOM Math argument 33 EEXIST File exists 17 EINVAL Invalid argument 22 EMFILE Too many open files 24 ENOENT No such file or directory 2 ENOEXEC Exec format error 8 ENOMEM Not enough memory 12 ENOSPC No space left on device 28 ERANGE Result too large 34 EXDEV Cross-device link 18 156 1

Jeżeli chcemy wyświetlić użytkownikowi komunikat z tekstem odpowiadającym kodowi błędu, to aby uzyskać ten komunikat, używamy funkcji: char *strerror( int errnum ); Funkcja zwraca tekst, który odpowiada opisowi kodu błędu. file = fopen(fname, "r"); if (file == NULL) { printf("error while trying to open '%s': %s\n", fname, strerror(errno));. Zamiast: file = fopen(fname, "r"); if (file == NULL) { printf("error while trying to open '%s': %s\n", fname, strerror(errno));. Można też napisać: file = fopen(fname, "r"); if (file == NULL) { printf("error while trying to open '%s': %s", fname, strerror(null));. Wtedy zostanie wypisany komunikat właściwy dla ostatniego wywołania, które wygenerowało błąd, zakończony znakiem nowej linii. 157 158 Standardowy strumień dla komunikatów o błędach: stderr Tam zwykle wypisujemy komunikaty o błędach, np.: fprintf( stderr, %s, Błąd otwarcia pliku ); W przypadku wystąpienia błędów przy wywołaniu funkcji bibliotecznych, zręczniej jest wysłać systemowy komunikat o błędzie do strumienia stderr za pomocą funkcji perror: void perror( const char *string ); Zmienna string zawiera komunikat użytkownika. Zaraz za nim zostanie wypisany komunikat systemowy o błędzie. Wywołanie: perror( Błąd otwarcia pliku" ); wypisze w oknie konsoli komunikat będący złożeniem dwóch komunikatu użytkownika i komunikatu systemowego : Błąd otwarcia pliku: No such file or directory 159 W trakcie działania na pomyślnie otwartym pliku (zapisywania lub odczytywania) mogą również pojawić się błędy. Aby je sprawdzić, używamy funkcji ferror int ferror( FILE *stream ); FILE * pfile; pfile=fopen("myfile.txt", wb"); if (pfile==null) perror ("Error opening file"); else { fwrite (buffer,sizeof(buffer),1,pfile); if (ferror (pfile)) perror ("Error writing to myfile.txt"); 160 Aby oczyścić wskaźnik błędu i wskaźnik końca pliku dla otwartego strumienia, należy użyć funkcji clearerr: void clearerr( FILE *stream ); Wskaźniki błędu i końca pliku nie są automatycznie czyszczone, ale pozostają póki nie zostanie wywołana funkcja clearerr, fseek, fsetpos, lub rewind. W przeciwnym razie każda kolejna próba działania na takim pliku będzie ciągle zwracała raz ustawiony kod błędu. 161 Wyszukiwanie błędów w nowym kodzie Oprócz błędów wynikających z zewnętrznych warunków w których pracuje program są jeszcze błędy, który źródłem jest sam autor kodu, tj. błędy związane z niepoprawnym zakodowaniem algorytmu Typowym błędem tego typu jest dopuszczenie do sytuacji, w której program nadał zmiennej wartość spoza zakresu przewidzianego przez programistę, tj. dla której nie ma właściwej obsługi i stąd program próbował: dzielić przez zero obliczyć pierwiastek z liczby ujemnej robić coś równie głupiego 162 2

Intuicyjnym rozwiązaniem jest dodanie sprawdzenia, czy zmienna ma wartość należąca do dozwolonego zakresu: void printd(int n) { if (n<=0) { /* n może mieć tylko wartości dodatnie */ printf( uwaga: n<=0!\n ); return; Takie sprawdzanie warunków zwiększa liczbę linii kodu, komplikuje kod i spowalnia działanie programu. Dodatkowe sprawdzenia stają się zbędne, kiedy już program jest wytestowany i wiadomo, że funkcja NIGDY nie zostanie wywołana z argumentem o wartości 0 lub mniejszej. Potrzebny jest prosty mechanizm, który będzie sprawdzał poprawność warunku logicznego, sygnalizował, kiedy jest nie spełniony, oraz znikał, kiedy tworzona jest finalna postać programu. void assert( int expression ); Funkcja pochodzi z biblioteki assert.h. Sprawdza wartość wyrażenia logicznego i jeżeli jest spełnione, nie robi nic. W przeciwnym przypadku przerywa działanie programu i wyrzuca komunikat do standardowego strumienia wyjściowego. Komunikat zawiera: treść warunku, nazwę pliku źródłowego i numer linii. 163 164 void printd(int n) { assert(n>0); Jeżeli zmienna n ma wartość większą od zera, nie dzieje się nic. W przeciwnym przypadku dostaniemy w oknie konsoli komunikat: Assertion failed: n>0, file main5.c, line 34 This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. Czy przerwanie działania programu to nie jest zbyt drastyczne rozwiązanie? W praktyce znacznie gorszym pomysłem byłoby dopuszczenie do dalszego działania programu w sytuacji, kiedy nie są prawdziwe podstawowe założenia projektanta. Program wymaga poprawek. Ten komunikat zawiera wszystkie niezbędne informacje, aby ułatwić programiście znalezienie błędu w swoim programie. 165 166 Użycie assert(n>0); jest prostsze i wymaga mniej pisania niż: if (n<=0) { printf( uwaga: n<=0! ); exit; Aby assert zadziałał, kompilacja kodu musi być wykonywana w trybie generującym dodatkowe informacje dla odpluskwiacza (debuggera). To pozwala np. na krokowe wykonanie kodu i obserwowanie wartości zmiennych w poszczególnych krokach wykonania, co jest przydatne podczas tworzenia i poprawiania kodu. Finalna wersja kodu (tzw. release) jest generowana zawsze przy wyłączonym trybie generowania dodatkowych informacji dla odpluskwiacza (wtedy program jest mniejszy i działa szybciej). W tym trybie kompilowania wszystkie wywołania assert są ignorowane przez kompilator i żaden kod dla wywołań tej instrukcji nie jest generowany. Ponadto znika w finalnej wersji programu. 167 168 3

Uwaga! Ponieważ po wyłączeniu trybu odpluskwiania asercje znikają z programu, nie wolno umieszczać w nich instrukcji dokonujących zmiany wartości zmiennych w programie, lub dokonujących jakichkolwiek innych działań na danych, np.: func(void) { int c; assert((c = getchar())!= EOF); putchar(c); Tryb kompilacji można ustawić poprzez napisanie odpowiedniej instrukcji w pliku programu Ta instrukcja to utworzenie określonej stałej. Tworzymy ją używając dyrektywy preprocesora #define Użycie #define - przykłady: #define MyName Krzysztof #define TrybCichy W drugim przypadku stała TrybCichy ma wartość pustą, ale istnieje, dlatego można teraz sprawdzać jej zdefiniowania pisząc: #ifdef TrybCichy #endif 169 170 Aby wyłączyć sprawdzanie asercji można przed odwołaniem się do biblioteki assert.h utworzyć stałą NDEBUG. #define NDEBUG #include <assert.h> Trzeba jednak być świadomym ewentualnych skutków ubocznych takiego postępowania. Jeżeli nie wiesz, jakie skutki może powodować w kodzie użycie dyrektyw wpływających na działanie kompilatora, to jest pierwszy powód, dla którego nie powinieneś ich używać. ISO/ANSI C Podział kodu programu na pliki 171 Duży kod warto dzielić na fragmenty o wspólnej funkcjonalności (np. funkcje numeryczne, funkcje we/wy, funkcje dostępu do plików, itp.) Fragmenty należy umieszczać w oddzielnych plikach. Pliki dołączamy do naszego pliku za pomocą dyrektywy #include, np.: #include "sortowanie.c" Połączenia dokonuje preprocesor kodu. 173 Łączenie przykład: Kod z pliku wskazanego przez #include jest łączony z kodem naszego pliku tworząc w momencie kompilacji postać pośrednią, tj. jedną dużą całość ułożoną sekwencyjnie wg kolejności dołączeń: Plik A.txt: Był skrzypek rodem z Prabutów, #include "B.txt" od skrzypiec zamiast butów. Plik B.txt: miał nogi za duże do butów. Wszystkie go uwierały, więc nosił futerały Jaki tekst wygeneruje preprocesor kodu przetwarzając plik A.txt? 174 4

Przy wielopoziomowych włączeniach kodu pojawia się problem. A korzysta z B i C. B korzysta z D i C korzysta z D. Wtedy D zostanie dołączony dwa razy. W finalnej postaci kodu całego programu przygotowanej przez preprocesor funkcje z D pojawią się dwa razy wystąpi błąd kompilacji. Rozwiązanie: należy włączać same deklaracje, a nie definicje funkcji. Natomiast definicje podać tylko raz, na końcu kodu programu. 175 Deklaracja: char flip(char, struct klucz ); Definicja: char flip(char c, struct klucz k) { int i; for(i=0;i<24; i++) if (c==k.mapa[i]) return k.mapa[(i+k.skok)%10]; return c; ; 176 Tworząc biblioteki, dla każdego zestawu funkcji tworzymy dwa pliki: z deklaracjami i z definicjami. Np. biblioteka z funkcjami do sortowania mogłaby mieć pliki: sortowanie.h i sortowanie.c w pliku z metodą main dołączamy tylko nagłówki, np.: #include "sortowanie.h" Jak i kiedy dołączamy plik z definicjami.c? Do tego służy projekt w środowisku programistycznym. W ramach zakładanego projektu wskazujemy wszystkie pliki.c oraz wszystkie pliki.h, które zawierają niezbędny kod naszego programu. Proces kompilacji jest dwuetapowy: 1. Poszczególne pliki *.c kompilowane są kolejno; kody funkcji bibliotecznych nie są jeszcze konieczne (wystarczą same nagłówki). 2. Pliki wynikowe kompilacji są łączone (linkowane) w jeden plik *.exe 177 178 libc.h libc.c #include "libc.h" libb.h #include "libc.h" libb.c #include "libb.h" liba.h #include "libc.h" liba.c #include "liba.h" Budowa pliku nagłówkowego *.h Co zrobić, żeby plik `libc.h nie został wklejony dwa razy? Wykorzystać funkcje preprocesora: #ifndef nazwapliku_h #define nazwapliku_h /* tutaj deklaracje funkcji */ #endif Preprocesor wklei plik `libc.h dwa razy podczas analizy pliku `main.c. Problem: A co z typami danych? main.c #include "liba.h" #include "libb.h" #define definiuje (tworzy) nową stałą nazwapliku_h #ifndef sprawdza, czy nie jest zdefiniowana stała nazwapliku_h. Jeżeli nie, włącza kod znajdujący się poniżej tej dyrektywy, do kodu wyjściowego. #endif znacznik końca tekstu objętego funkcją #ifndef 179 180 5

Budowa pliku nagłówkowego *.h Użycie dyrektyw #ifndef, #define, #endif gwarantuje, że niezależnie ile razy pojawi się dyrektywa #include "libc.h" treść pliku zostanie dołączona w tylko jednym egzemplarzu. Nazwy zmiennych, które definiujemy za pomocą preprocesora muszą być unikatowe podczas kompilacji projektu dla każdego używanego pliku. Najpopularniejszą metodą zapewnienia sobie unikatowych nazw zmiennych, jest używanie nazwy pliku dla zmiennej preprocesora. 181 Budowa pliku źródłowego *.c #include "nazwapliku.h" /* tutaj definicje funkcji */ 182 Alternatywą dla: #ifndef nazwapliku_h #define nazwapliku_h /* tutaj deklaracje funkcji */ #endif jest #pragma once zapobiega wielokrotnemu załączeniu treści całego pliku. Ale nie należy do standardu.. 183 Zmienne zewnętrzne Zmienne są widziane w kodzie znajdującym się poniżej ich deklaracji w obrębie bloku danych a najlepszym razie w obrębie pliku Zmienne zadeklarowane w pliku poza ciałem funkcji nazywane są zmiennymi globalnymi Aby zmienna globalna z jednego pliku była widziana w drugim, musi zostać zadeklarowana z modyfikatorem extern Zadeklarowanie: extern double x; stanowi informację dla kompilatora, że zmienna ta jest lub będzie zdefiniowana w innym pliku/module 184 Zmienne zewnętrzne Deklaracja z modyfikatorem extern to sytuacja, gdy deklaracja zmiennej nie jest związana z jej definicją: żadna zmienna nie jest tworzona, tzn. pamięć nie jest przydzielana. Ta sama zmienna może być zadeklarowana jako extern wiele razy w wielu plikach, ale zdefiniowana może być tylko raz. Zmiennej deklarowanej nie wolno inicjować: extern double x = 0; /* Nie! */ Po takiej inicjalizacji kompilator zignoruje słowo kluczowe extern i potraktuje powyższa deklarację jak definicję. Kompilator po znalezieniu właściwej definicji nie zwróci komunikatu o błędzie, ponieważ będzie ona znajdowała się w innym pliku, a więc będzie ona traktowana jako definicja innej zmiennej, co prawda o tej samej nazwie, ale innej bo w innym pliku. ISO/ANSI C zakończenie 185 6

Odczyt i zapis bieżącej daty i czasu odbywa się za pomocą funkcji zdefiniowanych w bibliotece <time.h> Zdefiniowane są tam następujące typy i stałe: CLOCKS_PER_SEC liczba tyknięć na sekundę clock_t, time_t typy arytmetyczne do reprezentacji czasu struct tm { int tm_sec /* liczba sekund [0-61] (61 pozwala na 2 sekundy przestępne)*/ int tm_min /* liczba minut [0-59] */ int tm_hour /* liczba godzin po północy [0-23] */ int tm_mday /* dzień miesiąca [1-31] */ int tm_mon /* miesiąc w roku [0-11] */ int tm_year /* bieżący rok-1900 */ int tm_wday /* nr dnia licząc od niedzieli [0-6] */ int tm_yday /* nr dnia licząc od pierwszego stycznia [0-365] */ int tm_isdst /* znacznik uwzględniania czasu zimowego i letniego */ Struktura używana do reprezentacji czasu kalendarzowego 187 Sekunda przestępna, nazywana też sekundą skokową dodatkowa sekunda dodawana czasem (zwykle w czerwcu lub w grudniu) w celu zsynchronizowania uniwersalnego czasu koordynowanego ze średnim czasem słonecznym. https://www.gum.gov.pl/pl/wiadomosci/informacje-i-komunikaty/sekunda-przestepna/ 188 clock_t clock(void); Zwraca liczbę tyknięć od chwili uruchomienia danego procesu. Aby dostać liczbę sekund należy podzielić tą wartość przez CLOCKS_PER_SEC double difftime( time_t timer1, time_t timer0 ); Różnica w sekundach pomiędzy dwoma wskazaniami czasu time_t time( time_t *timer ); Aktualny czas systemowy Uwaga: zmienna typu time_t reprezentuje wskazania czasu od północy, 1 stycznia 1970 do 3:14:07, 19 stycznia 2038 time_t start, finish; long loop; double result, elapsed_time; time( &start ); for( loop = 0; loop < 500000000; loop++ ) result = 3.63 * 5.27; time( &finish ); elapsed_time = difftime( finish, start ); 189 190 time_t mktime( struct tm *timeptr ); Konwertuje dane zapisane w strukturze reprezentującej typ kalendarzowy do postaci wskazania czasu typu time_t char *asctime( const struct tm *timeptr ); Konwertuje dane zapisane w strukturze reprezentującej typ kalendarzowy do postaci tekstowej, np.: Sun Feb 03 11:38:58 2002 struct tm *localtime( const time_t *timer ); Konwertuje wskazanie czasu na typ kalendarzowy wg czasu lokalnego struct tm *gmtime( const time_t *timer ); Konwertuje wskazanie czasu typu time_t do postaci struktury tm struct tm *newtime; time_t aclock; time( &aclock ); /* odczytaj czas */ newtime = localtime( &aclock ); /* Konwertuj do postaci struct tm */ /* Wypisz czas lokalny w oknie konsoli */ printf( Bieżąca data i czas: %s", asctime( newtime ) ); 191 192 7

size_t strftime( char *strdest, size_t maxsize, const char *format, const struct tm *timeptr ); Formatuje zapis tekstowy daty i czasu %a Abbreviated weekday name %A Full weekday name %b Abbreviated month name %B Full month name %c Date and time representation appropriate for locale %d Day of month as decimal number (01 31) %H Hour in 24-hour format (00 23) %I Hour in 12-hour format (01 12) %j Day of year as decimal number (001 366) %m Month as decimal number (01 12) %M Minute as decimal number (00 59) %p Current locale's A.M./P.M. indicator for 12-hour clock %S Second as decimal number (00 59) %U Week of year as decimal number, with Sunday as first day of week (00 53) %w Weekday as decimal number (0 6; Sunday is 0) %W Week of year as decimal number, with Monday as first day of week (00 53) %x Date representation for current locale %X Time representation for current locale %y Year without century, as decimal number (00 99) %Y Year with century, as decimal number %z, %Z Either the time-zone name or time-zone abbreviation, depending on registry settings; no chars if time zone is unknown %% Percent sign 193 time_t rawtime; struct tm * timeinfo; char buffer [80]; time ( &rawtime ); timeinfo = localtime ( &rawtime ); strftime (buffer,80, "Teraz jest %I:%M%p.", timeinfo); puts (buffer); Na wyjściu: Teraz jest 03:21PM. 194 Zmienne systemowe (PATH, LIB, itd.) można odczytać używając funkcji getenv char *getenv( const char *varname ); char *pathvar; pathvar = getenv( "PATH" ); if( pathvar!= NULL ) printf( "PATH variable is: %s\n", pathvar ); Polecenie systemowe można wywołać używając funkcji system int system( const char *command ); system( "type crt.txt" ); /* wypisuje w oknie konsoli zawartość pliku tekstowego crt.txt */ 195 196 Aby zakończyć działanie programu musi być wykonana instrukcja: exit, abort, lub return w funkcji main void abort( void ); Przerywa działanie programu, nie zwraca sterowania do procesu nadrzędnego ale wyświetla komunikat: void exit( int status ); Funkcja kończy działanie programu w trybie prawidłowego zakończenia Standardowo przyjmuje się dwie wartości status: 0 (EXIT_SUCCESS) program zakończony prawidłowo; 1 (EXIT_FAILURE) - program zakończony niepoprawnie This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. exit( 0 ); 197 198 8

Funkcja exit przez wyjściem z programu wywołuje wszystkie funkcje wskazane wywołaniem funkcji atexit. Może być ich do 32. void fn1(void) { printf( "do jutra.\n" ); void fn2(void) { printf( Do widzenia " ); int main( void ) { atexit( fn1 ); atexit( fn2 ); exit( 0 ); /* Co pojawi się w oknie konsoli? */ Koniec części wykładu dotyczącej ISO/ANSI C 199 9