Dílčí příklady použití jazykových konstrukcí v projektu. Jazyk C Příklady. Pravidla překladu v gmake. Zadání

Podobné dokumenty
Část 2 Příklad načítání grafu, kompilace a projekt s více soubory. Část 3 Zadání 9. domácího úkolu (HW09)

Stromy. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 10 B0B36PRP Procedurální programování

Stromy. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 10 B0B36PRP Procedurální programování

Operační systémy. Cvičení 4: Programování v C pod Unixem

Algoritmizace a programování

Aplikace Embedded systémů v Mechatronice. Michal Bastl A2/713a

Základy programování (IZP)

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Základy programování (IZP)

Správné vytvoření a otevření textového souboru pro čtení a zápis představuje

Práce se soubory. Základy programování 2 Tomáš Kühr

Strukturu lze funkci předat: (pole[i])+j. switch(výraz) velikost ukazatele

IUJCE 07/08 Přednáška č. 6

6. lekce Úvod do jazyka C knihovny datové typy, definice proměnných základní struktura programu a jeho editace Miroslav Jílek

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

Programování v C++ 1, 1. cvičení

Koncepce (větších) programů. Základy programování 2 Tomáš Kühr

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Práce se soubory. Úvod do programování 2 Tomáš Kühr

Operační systémy. Cvičení 3: Programování v C pod Unixem

Jazyk C práce se soubory. Jan Hnilica Počítačové modelování 16

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Preprocesor a koncepce (větších) programů. Úvod do programování 2 Tomáš Kühr

Př. další použití pointerů

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

Základní datové struktury

Práce se soubory. Úvod do programování 2 Tomáš Kühr

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

IUJCE 07/08 Přednáška č. 4. v paměti neexistuje. v paměti existuje

Programování v jazyce C pro chemiky (C2160) 6. Funkce, struktury

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Základy programování (IZP)

Programování v jazyce C pro chemiky (C2160) 10. Grafická knihovna g2

Základy programování (IZP)

Semestrální práce KIV/PC Řešení kolizí frekvencí sítě vysílačů Zdeněk Bečvář A14B0466P 10. ledna 2016

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

2 Datové typy v jazyce C

Struktura programu v době běhu

Základy programování (IZP)

Práce s binárními soubory. Základy programování 2 Tomáš Kühr

Embedded vývoj v Clutteru a Mx

- dělají se také pomocí #define - podobné (použitím) funkcím - předpřipravená jsou např. v ctype.h. - jak na vlastní makro:

IUJCE 07/08 Přednáška č. 1

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE LEXIKÁLNÍ ANALÝZA

PROGRAMOVÁNÍ V C++ CVIČENÍ

Aplikace Embedded systémů v Mechatronice. Michal Bastl A2/713a

Pokročilé programování v jazyce C pro chemiky (C3220) Vstup a výstup v C++

Ukazatele, paměťové třídy, volání funkcí

dostat zdroják Petr Zemek Fakulta informačních technologií VUT v Brně izemek

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Třídy a struktury v C++

8 Třídy, objekty, metody, předávání argumentů metod

Algoritmizace a programování

Např.: // v hlavičkovém souboru nebo na začátku // programu (pod include): typedef struct { char jmeno[20]; char prijmeni[20]; int rok_nar; } CLOVEK;

Reprezentace dat v informačních systémech. Jaroslav Šmarda

Základy programování (IZP)

Algoritmizace a programování

Prioritní fronta a příklad použití v úloze hledání nejkratších cest

Rozsáhlé programy = projekty

int => unsigned int => long => unsigned long => float => double => long double - tj. bude-li:

Programování v jazyce C pro chemiky (C2160) 4. Textové řetězce, zápis dat do souboru

Část I. Část 1 Prioritní fronta (Halda) Přehled témat. Prioritní fronta a příklad použití v úloze hledání nejkratších cest

Algoritmizace a programování

Programování v jazyce C pro chemiky (C2160) 5. Čtení dat ze souboru

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Pole stručný úvod do začátku, podrobně později - zatím statická pole (ne dynamicky) - číslují se od 0

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Lekce 19 IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ JAZYK C

Základy C++ I. Jan Hnilica Počítačové modelování 18

Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

Bitové operátory a bitová pole. Úvod do programování 2 Tomáš Kühr

Odvozené a strukturované typy dat

Programovací jazyk C(++) C++ area->vm_mm->locked_vm -= len >> PAGE_SHIFT;

Část 1 Prioritní fronta polem a haldou

Abstraktní datový typ

Část I. Část 1 Abstraktní datový typ. Přehled témat. Abstraktní datový typ. Zdroje

Struktury a dynamická paměť

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Jazyk C Část II. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 9 A0B36PR2 Programování 2

Dynamická vícerozměrná pole. Základy programování 2 Tomáš Kühr

IUJCE Přednáška č. 11. další prvky globální proměnné, řízení viditelnosti proměnných, funkcí

Programování v jazyce C a C++

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. December 7, 2016

Základy programování (IZP)

Část 1 Příklad Pracujeme s ukazateli. Jazyk C Část II. Část 3 Jazyk C - základní knihovny, dynamická alokace paměti, soubory

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Část I. Část 1 Příklad Pracujeme s ukazately

Jazyk C Část II. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 9 A0B36PR2 Programování 2

Úvod do programovacích jazyků (Java)

Abstraktní datový typ

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

PROGRAMOVÁNÍ V JAZYCE C V PŘÍKLADECH 11 Dynamické datové struktury 11.1 Spojové struktury Příklad PROG_

Příkazy preprocesoru - Před překladem kódu překladačem mu předpřipraví kód preprocesor - Preprocesor vypouští nadbytečné (prázdné) mezery a řádky -

x86 assembler and inline assembler in GCC

Část 1 Abstraktní datový typ. Datové struktury a abstraktní datový typ

Spojová implementace lineárních datových struktur

Abstraktní třídy, polymorfní struktury

Práce s pamětí a předávání parametrů. Úvod do programování 1

1. Programování proti rozhraní

Transkript:

Dílčí příklady použití jazykových konstrukcí v projektu Jazyk C Příklady Jan Faigl Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Přednáška 10 A0B36PR2 Programování 2 Program složený z více souborů Dynamická alokace paměti Načítání souboru Parsování čísel z textového souboru Měření času běhu programu Řízení kompilace projektu složeného z více souborů Makefile Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 1 / 19 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 2 / 19 Zadání Vytvořte program, který načte orientovaný graf definovaný posloupností hran Graf je zapsán v textovém souboru Navrhněte datovou strukturu pro reprezentaci grafu Počet hran není dopředu znám Zpravidla však budou na vstupu grafy s průměrným počtem hran 3n pro n vrcholů grafu. Hrana je definována číslem vstupního a výstupního vrcholu a cenou (také celé číslo) Ve vstupním souboru je každá hrana zapsaná samostatně na jednom řádku Řádek má tvar: from to cost kde from, to a cost jsou kladná celá čísla v rozsahu int Pro načtení hodnot hran použijte pro zjednodušení funkci fscanf() Program dále rozšiřte o sofistikovanější, méně výpočetně náročné načítání Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 3 / 19 Pravidla překladu v gmake Pro řízení překladu použijeme předpis programu GNU make Pravidla se zapisují do souboru Makefile make nebo gmake http://www.gnu.org/software/make/make.html Pravidla jsou deklarativní ve tvaru definice cíle, závislostí cíle a akce, která se má provést cíl : závislosti dvojtečka akce tabulátor Cíl (podobně jako závislosti) může být například symbolické jméno nebo jméno souboru tload.o : tload.c clang -c tload.c -o tload.o Předpis může být napsán velmi jednoduše Například jako v uvedené ukázce. Flexibilita použití však spočívám především v použití zavedených proměnných, vnitřních proměnných a využití vzorů, neboť většina zdrojových souborů se překládá identicky. Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 4 / 19

Příklad Makefile Definujeme pravidlo pro vytvoření souborů.o z.c Definice přeložených souborů vychází z aktuálních souborů v pracovním adresáři s koncovkou.c CC:=ccache $(CC) CFLAGS+=-O2 OBJS=$(patsubst %.c,%.o,$(wildcard *.c)) TARGET=tload bin: $(TARGET) $(OBJS): %.o: %.c $(CC) -c $< $(CFLAGS) $(CPPFLAGS) -o $@ $(TARGET): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) -o $@ clean: $(RM) $(OBJS) $(TARGET) ccache CC=clang make vs CC=gcc make Při linkování záleží na pořadí souborů (knihoven)! Jednou z výhod dobrých pravidel je možnost paralelního překladu nezávislých cílů make -j 4 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 5 / 19 Pomocné funkce pro práci s grafem Alokaci/uvolnění grafu implementujeme v samostatných funkcích Při načítání grafu budeme potřebovat postupně zvyšovat paměť pro uložení načítaných hran Proto využijeme dynamické alokace paměti pro nafukování paměti pro uložení hran grafu enlarge_graph() o nějakou definovanou velikost #ifndef GRAPH_UTILS_H #define GRAPH_UTILS_H graph_t* allocate_graph(void); void free_graph(graph_t **g); graph_t* enlarge_graph(graph_t *g); void print_graph(graph_t *g); Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 7 / 19 Definice datové struktury grafu graph.h Zavedeme nový typ datové struktury hrana edge_t, který použijeme ve struktuře grafu graph_t #ifndef GRAPH_H #define GRAPH_H typedef struct { int from; int to; int cost; edge_t; typedef struct { edge_t *edges; int length; int size; graph_t; Soubor budeme opakovaně vkládat (include) v ostatních zdrojových souborech, proto zabraňujeme opakované definici konstantou preprocesoru GRAPH_H Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 6 / 19 Alokace paměti pro uložení grafu Testujeme úspěšnost alokace paměti assert() Po alokaci nastavíme hodnoty proměnných na NULL a 0 #include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> graph_t* allocate_graph(void) { graph_t *g = (graph_t*) malloc(sizeof(graph_t)); g->edges = NULL; g->length = 0; g->size = 0; /* or we can call calloc */ return g; Alternativně můžeme použít funkci calloc() Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 8 / 19

Uvolnění paměti pro uložení grafu Testujeme validní hodnotu argumentu funkce assert() Pokud se stane chyba, tak funkci v programu špatně voláme. Až program odladíme můžeme kompilovat s NDEBUG. void free_graph(graph_t **g) { assert(g!= NULL && *g!= NULL); if ((*g)->size > 0) { free((*g)->edges); free(*g); *g = NULL; Po uvolnění paměti nastavíme hodnotu ukazatele na strukturu na hodnotou NULL Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 9 / 19 Zvětšení paměti pro uložení hran grafu V případě nulové velikosti alokujme paměť pro NSIZE hran NSIZE můžeme definovat při překladu #ifndef NSIZE #define NSIZE 10 např. clang -D NSIZE=100 -c graph_utils.c graph_t* enlarge_graph(graph_t *g) { int n = g->size == 0? NSIZE : g->size * 2; /* double the memory */ edge_t *e = (edge_t*)malloc(n * sizeof(edge_t)); memcpy(e, g->edges, g->length * sizeof(edge_t)); free(g->edges); g->edges = e; g->size = n; return g; Místo alokace nového bloku paměti a kopírování původního obsahu můžeme použít funkci realloc() Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 10 / 19 Tisk hran grafu Pro tisk hran grafu využijeme pointerovou aritmetiku void print_graph(graph_t *g) { fprintf(stderr, "Graph has %d edges and %d edges are allocated\n", g->length, g->size); edge_t *e = g->edges; for(int i = 0; i < g->length; ++i, e++) { printf("%d %d %d\n", e->from, e->to, e->cost); Informace vypisujeme na standardní chybový výstup Graf tiskneme na standardní výstup Při tisku a přesměrování standardního výstupu tak v podstatě můžeme realizovat kopírování souboru s grafem Např../tload -p g > g2 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 11 / 19 Hlavní funkce programu main V hlavní funkci zpracujeme předané argumenty programu V případě uvedení přepínače -p vytiskneme graf na stdout int main(int argc, char *argv[]) { int ret = 0; int print = 0; char *fname; int c = 1; if (argc > 2 && strcmp(argv[c], "-p") == 0) { print = 1; c++; fname = argc > 1? argv[c] : NULL; fprintf(stderr, "Load file %s \n", fname); graph_t *graph = allocate_graph(); int e = load_graph_simple(fname, graph); fprintf(stderr, "Load %d edges\n", e); if (print) { print_graph(graph); free_graph(&graph); return ret; Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 12 / 19

Jednoduché načtení grafu deklarace Prototyp funkce uvedeme v hlavičkovém souboru load_simple.h #ifndef LOAD_SIMPLE_H #define LOAD_SIMPLE_H int load_graph_simple(const char *fname, graph_t *g); Vkládáme pouze soubor graph.h pro definici typu graph_t Snažíme se zbytečně nevkládat nepoužívané soubory Jednoduché načtení grafu implementace 1/2 Používáme funkci enlarge_graph, proto vkládáme graph_utils.h #include <stdio.h> #include "graph_utils.h" int load_graph_simple(const char *fname, graph_t *g) { int c = 0; int exit = 0; FILE *f = fopen(fname, "r"); while(!feof(f) &&!exit) { if (g->length == g->size) { enlarge_graph(g); edge_t *e = g->edges + g->length; while(!feof(f) && g->length < g->size) { /* read and parse a single line -> NEXT SLIDE! */ fclose(f); return c; load_simple.h vkládat nemusíme, obsahuje pouze prototyp funkce Obecně je to však dobrý zvykem nebo nutností (definice typů) Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 13 / 19 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 14 / 19 Jednoduché načtení grafu implementace 2/2 Pro načtení řádku s definicí hrany použijeme funkci fscanf() while(!feof(f) && g->length < g->size) { int r = fscanf(f, "%d %d %d\n", &(e->from), &(e->to ), &(e->cost)); if (r == 3) { g->length++; c++; /* pocet nactenych hran */ e++; /* posun ukazatele grafu o sizeof(edge_t)*/ else { exit = 1; /* neco je spatne ukoncujeme naciteni */ break; Kontrolujeme počet přečtených parametrů a až pak zvyšujeme počet hran v grafu Spuštění programu 1/3 Nechť máme soubor g definující graf o 1 000 000 uzlech % du g 62M g brettonia%./tload g Velikost souboru cca 62 MB (příkaz du disk usage) % time./tload g./tload g 1.12s user 0.03s system 99% cpu 1.151 total Příkazem time můžeme změřit potřebný čas běhu programu strojový, systémový a reálný Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 15 / 19 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 16 / 19

Spuštění programu 2/3 Příznakem -p a přesměrováním standardního výstupu můžeme vytisknout graph do souboru V podstatě vstupní soubor zkopírujeme. % time./tload -p g > g2 Graph has 2998898 edges and 5242880 edges are allocated./tload -p g > g2 2.09s user 0.07s system 99% cpu 2.158 total % md5 g g2 MD5 (g) = d969461a457e086bc8ae08b5e9cce097 MD5 (g2) = d969461a457e086bc8ae08b5e9cce097 Čas běhu programu je přibližně dvojnásobný Oba soubory se zdají být z otisku md5 identické Na Linuxu md5sum případně lze použít otisk sha1, sha256 nebo sha512 Spuštění programu 3/3 Implementací sofistikovanějšího načítání % /usr/bin/time./tload g 0.19 real 0.16 user 0.03 sys lze získat výrazně rychlejší načítání % /usr/bin/time./tload g 1.15 real 1.05 user 0.10 sys 160 ms vs 1100 s Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 17 / 19 Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 18 / 19 Jak a za jakou cenu zrychlit načítání seznamu hran Zrychlit načítání můžeme přijmutím předpokladů o vstupu Při použití fscanf() je nejdříve načítán řetězec (řádek) pak řetěz reprezentující číslo a následně je parsováno číslo Převod na číslo je napsán obecně Můžeme použití postupné bufferované načítání Převod na číslo můžeme realizovat přímo po přečtení tokenu parsováním znaků (číslic) načtené posloupnosti bytů v obráceném pořadí Můžeme získat výrazně rychlejší kód, který je však komplexnější a pravděpodobně méně obecný Jan Faigl, 2016 A0B36PR2 Přednáška 10: Jazyk C Příklady 19 / 19