1 / 23

8. přednáška 27. 3. 2008 -typedef - preprocesor Studijní materiály najdete na adrese:

8. přednáška 27. 3. 2008 -typedef - preprocesor Studijní materiály najdete na adrese: http://www.uai.fme.vutbr.cz/~vdumek/. Typedef. - pro zpřehlednění deklarací nových typů typedef typ identifikátor_typu

ryo
Download Presentation

8. přednáška 27. 3. 2008 -typedef - preprocesor Studijní materiály najdete na adrese:

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 8. přednáška 27. 3. 2008 -typedef - preprocesor Studijní materiály najdete na adrese: http://www.uai.fme.vutbr.cz/~vdumek/

  2. Typedef • - pro zpřehlednění deklarací nových typů • typedef typ identifikátor_typu • - pomocí tohoto příkazu nevytvoříme nový sémantický typ, pouze tvoříme nové jméno pro existující datový typ (omezení spojená s původním typem zůstávají) • - používá se hlavně pro zvýšení přehlednosti a čitelnosti programů, pro usnadnění změn typů (operátor přetypování) a snazší modifikaci typů • typedef int LENGTH; • typedef float *P_FLOAT; • P_FLOAT p_m, p_n; /* použití */ • typedef char *STRING; • typedef int (*PFI)(); /* ukazatel na funkci */

  3. Typedef - dává možnost definovat nové typy, kterým můžeme deklarovat proměnné, zlepší se čitelnost programů, změny se dají dělat z jednoho místa int f1(); int f1(); funkce vracející int typedef int *intuk; int *u1; intuk u1; ukazatel na int int *f2(); intuk f2(); fce vracející ukazatel na int typedef int far *faruk; int far *u2; faruk u2; vzdálený ukazatel na int int far *f3(); faruk f3(); funkce vracející vzdálený ukazatel na int typedef int (*fnuk1)(int); int (*fu1)(int); fnuk1 fu1; ukazatel na fci s jedním int parametrem, která vrací int typedef int (*fnuk2)(intuk); int (*fu2)(int *iu); fnuk2 fu2; ukazatel na fci s parame- trem směrník na int, která vrací int

  4. Preprocesor - úprava zdrojového textu před vlastním překladem - rozvoj maker - náhrada symbolicky označených částí skutečným textem - substituce textu - podmíněný překlad - výběr z různých variant podle podmínek - vložené soubory - možnost před překladem přidat soubor - odstraňuje komentáře, nadbytečné mezery, tabelátory - činnost preprocesoru je řízena direktivami, které jsou na tzv. řídicíchřádcích (označení #), řídicí řádek může obsahovat i komentář - u moderních překladačů není fáze předzpracování oddělená, ne- vzniká žádný výstupní text, pokud je potřeba, používá se samo- statný program (CPP -> přípona .I) Definice konstant a maker - možnost symbolického pojmenování konstant, příkazů, výrazů, … možnost modifikovat textové náhrady pomocí parametrů

  5. test.c test.i void main(void) { // komentar #define DESET 10 #define SYMBOL if(DESET == 9) printf("ahoj"); /* dalsi komentar */ } test.cpp 1: void main(void) test.cpp 2: { test.cpp 3: test.cpp 4: test.cpp 5: test.cpp 6: test.cpp 7: if(10 == 9) test.cpp 8: printf("ahoj"); test.cpp 9: test.cpp 10: test.cpp 11: } test.cpp 12: CPP

  6. Preprocesor #define - používá se k definici konstant a maker #define symbol - takto definovaný symbol nemá žádnou hodnotu, pouze existuje, lze jej použít pro řízení podmíněného překladu (direktiva #ifdef) #define jméno_makra text - text vzniklý náhradou makra se nazývá rozvoj makra, text po první mezeře za identifikátorem, pozor na poznámky, nahrazování se neprovádí v řetězcích #define DESET 10 /* konstanta - symbolické jméno pro hodnotu 10 */ #define beep putch(7) /* symbolické označení pro výpis znaku BELL */ if (k == DESET) beep; rozvine se if(k == 10) putch(7); - dosazení hodnoty se provádí na úrovni textu před překladem

  7. Preprocesor - při ukončení definice se nepoužívá středník, symbol se nahradí textem při rozvoji, středník se použije v místě použití - definice se dá použít i na více řádků #define DLOUHY_TEXT “Toto je velmi dlouhy text, který se nevejde ani za nic na \ jeden radek “ #define CHYBA if (chyba==1) \ printf(“\nstala se nejaka chyba”); \ else if (chyba==2) \ printf(“\nstala se nejaka jina chyba”); \ else \ printf(“\nstala se uplne jina chyba”); - definice makra s parametry #define jmeno_makra(seznam formalnich parametru) text - pozor na umístění mezer

  8. #include <stdio.h> #define DLOUHY_TEXT "Toto je velmi dlouhy text, kterě se nevejde ani za nic \ na jeden radek" #define CHYBA if (chyba==1) \ printf("\nstala se nejaka chyba"); \ else if (chyba==2) \ printf("\nstala se nejaka jina chyba"); \ else \ printf("\nstala se uplne jina chyba"); void main(void) { chyba=2; printf ("%s", DLOUHY_TEXT); CHYBA chyba=1; CHYBA } Toto je velmi dlouhy text, který se nevejde ani za nic na jeden radek stala se nejaka jina chyba stala se nejaka chyba

  9. Preprocesor • - volání makra je formálně shodné s voláním funkce (mnoho knihovních funkcí jsou ve skutečnosti makra), počet formálních a skutečných parametrů musí souhlasit • zdánlivě nadbytečné množství závorek zamezí chybám při rozvoji maker v případě použití složených výrazů nebo v souvislosti s prioritou operátorů #define MAX(a,b) (((a) > (b)) ? (a) : (b)) i=MAX(3, y); i=(((3) > (y)) ? (3) : (y)); #define NA_DRUHOU(x) x*x špatně i = 6; j = NA_DRUHOU(i); j = 6*6; /* 36 OK */ k = NA_DRUHOU(i+2); k = i+2*i+2; /* 20 CHYBA */ l = 100/NA_DRUHOU(5); l = 100/5*5; /* 100 CHYBA */ #define NA_DRUHOU(x) ((x)*(x)) správně

  10. Preprocesor - totožná syntaxe volání funkce a makra může vést k chybám, neboť u maker není prováděna (na rozdíl od funkcí) žádná typová kontrola, není předávána hodnota parametru, ale jeho textová podoba, zrychluje se běh programu #define NA_DRUHOU(x) ((x)*(x)) int na_druhou(int x) { return x*x; } ….. i = 2; j = NA_DRUHOU(i++); /* j=((i++)*(i++))=2*3=6, i=4 */ ….. i = 2; k = na_druhou(i++); /* k=4, i=3 */ - definovaný symbol nemůže být definován znovu

  11. Preprocesor - makra mohou být vnořována, po rozvoji makra projde prepro- cesor vzniklý text ještě jednou, aby mohl provést event. rozvoj dalšího makra #define NA_DRUHOU(x) ((x)*(x)) #define MAX(a,b) (((a)>(b)) ? (a) : (b)) i = MAX(k, NA_DRUHOU(j)); po rozvoji: i = (((k) > (NA_DRUHOU(j))) ? (k) : (NA_DRUHOU(j))); i = (((k) > (((j)*(j)))) ? (k) : (((j)*(j)))); - rozvoj makra nesmí vést na další direktivu, která již není pre- procesorem zpracována #define VLOZENI #include <stdio.h> VLOZENI se rozvine jako #include <stdio.h> /* chyba */

  12. Preprocesor - jako jména maker lze použít i klíčová slova. Využívání této vla- stnosti se nedoporučuje #define int long /* formálně správně, zcela nevhodné */ - parametry maker se dosazují buď přímo jako text, který se přidá do zdrojového textu programu, nebo mohou být napřed převe- deny na textový řetězec. K tomu se používá symbol #. #define VYSLEDEK(x) printf(#x “=%f\n”, x) VYSLEDEK(Obvod); /* printf(“Obvod” “=%f\n”, Obvod); - při chybné definici makra může dojít k chybné interpretaci zá- měrů programátora #define VYSLEDEK_1(x) printf(“x=%f\n”, x); ….. VYSLEDEK_1(Obvod); /* printf(“x=%f\n”, Obvod); */

  13. Preprocesor - symbol definovaný pomocí direktivy #define platí až do konce překládaného modulu (včetně vkládaných modulů), pokud se ne- vyskytne direktiva #undef #undef jmeno_makra pokud mělo rušené makro parametry, tyto se neuvádějí. Symboly přestávají existovat, vrací se do stavu před použitím #define. Lze testovat pomocí #ifdef, #ifndef u podmíněného překladu. - symbol lze definovat po direktivě #undef zcela jiným způsobem, při pokusu o novou definici bez předchozího použití #undef je hlášena chyba #define DELKA_BLOKU 512 ….. delka=pocet*DELKA_BLOKU; /* pocet * 512 */ ….. #undef DELKA_BLOKU /* dale nelze pouzivat */

  14. Preprocesor #define DELKA_BLOKU 128 ….. delka=pocet*DELKA_BLOKU; /* pocet * 128 */ ….. Vložené soubory - lze vložit do zdrojového souboru text, obsažený v jiném souboru samotná direktiva #include je odstraněna #include <jmeno_souboru> #include “jmeno_souboru” - jméno souboru může být uvedeno včetně specifikace cesty k souboru, to má význam u syntaxe s uvozovkami, pro úhlové zá- vorky platí předdefinovaný adresář s vkládanými soubory - direktiva include se nepoužívá pouze pro hlavičkové soubory, ale je použitelná i pro zdrojové texty

  15. Preprocesor S1.C S2.C #define KOLIK 20 #include “S1.C” typedef struct { int i,j,k; MOJE_STR a, b, *c; float d; int p=KOLIK; char a[20]; } MOJE_STR; void main(void) { void moje_funkce(MOJE_STR *x, int a) ….. {…..} moje_funkce(&a, KOLIK); ….. } - vlivem vložení souboru S1.C do souboru S2.C lze používat všechny proměnné a funkce, probíhá zde jeden překlad - ANSI překladače (C++) povolují i vkládání makra - může být i vnoření (8), pozor na cyklické vnoření #define myinclude “hlavicka.h” #include myinclude/* vkládá se hlavicka.h */ #include “myinclude.h” /* vkládá se myinclude.h */

  16. Preprocesor - direktiva #include se používá pro vkládání souborů s definicemi maker, konstant, datových typů, deklaracemi globálních promě- nných a prototypy funkcí, hlavičkové soubory, rozdělení pro různé problematické okruhy - zmenšení překládaných objemů Podmíněný překlad - mechanismus k vyřazení některé části zdrojového textu z přek- ladu na základě splnění nějaké podmínky. Vyřazovaná část je nahrazena prázdnými řádky. Používají se direktivy: #if, #ifdef, #ifndef, #elif, #else, #endif Nejjednodušší forma: #if konst_vyraz ….. /* podmíněně překládaný text */ #endif

  17. Preprocesor • - úsek mezi direktivami je překládán pouze tehdy, když má konstantní výraz nenulovou hodnotu, každé if musí mít své endif a musí být obě ve stejném překládaném souboru • - výraz, který řídí překlad musí být vyčíslitelný v době překladu, nesmí obsahovat proměnné, sizeof, enum a casting • jako podmínka pro řízení překladu se často používá test, zda je nějaký symbol definován #define BLOK 512 #define POCET 3 ….. #if BLOK > 200 ….. /* preklad OK */ #endif ….. /* preklad vzdy */ #if (BLOK == 128) && (POCET > 2) ….. /* nepreklada se */ #endif ….. /* preklad vzdy */

  18. #ifdef symbol ….. /* preklada se , pokud je symbol definovany */ #endif ….. #ifndef symbol ….. /* preklada se, pokud symbol neni definovany */ #endif #if defined symbol /* totez jako #ifdef symbol */ #if defined (symbol) /* totez, zavorky jsou nepovinne */ #if !defined symbol /* totez jako #ifndef */ - výhodou direktivy defined je možnost testovat definici více symbolů pomocí jedné direktivy #define SYMBOL1 #define SYMBOL2 #if defined SYMBOL1 && !defined SYMBOL2 ….. /* nepreklada se */ #endif #undef SYMBOL2 #if defined SYMBOL1 && !defined SYMBOL2

  19. Preprocesor - pokud má mít generovaný kód v některém úseku v závislosti na určitých podmínkách více než dvě varianty, používá se vedle if a else ještě elif #if konst_vyraz1 ….. /* překládá se pro pravdivý konst_vyraz1 */ #elif konst_vyraz2 ….. /* překládá se pro !konst_vyraz1 && konst_vyraz2 */ #elif konst_vyraz3 ….. /* !konst_vyraz1 && !konst_vyraz2 && konst_vyraz3 */ #else ….. /* překládá se, pokud není pravdivý žádný výraz */ #endif - počet direktiv elif není omezen, pro každou direktivu if ale může být nejvýše jedna direktiva else, je poslední řídící direktivou před endif - podmíněně překládané sekce mohou být v rámci zdrojového tex- tu vnořovány do libovolné hloubky, každá if musí mít odpoví- dající endif

  20. Preprocesor #if SYMBOL<50 ….. /* překládá se pro <50 */ #elif SYMBOL<300 ….. /* překládá se pro 50<=SYMBOL<300 */ #elif SYMBOL<1000 ….. /* překládá se pro 300<=SYMBOL<1000 */ #else ….. /* překládá se pro 1000<=SYMBOL */ #endif #define X 10 #define Y 80 ….. #if X<25 ….. /* překládá se pro X<25 */ #if Y>100 ….. /* překládá se pro (X<25)&&(Y>100) */ #endif /* ukončení podmínky Y>100 */ ….. #endif /* ukončení podmínky X<25 */

  21. Preprocesor - podmíněný překlad používáme v případech, kdy potřebujeme generování různých variant kódu z jediného zdrojového textu (různé kompilátory, různé operační systémy, různé paměťové modely) Ovládání čísel řádků - překladač i preprocesor si během své práce pamatují jméno právě zpracovávaného zdrojového souboru a číslo právě zpra- covávaného řádku tohoto souboru. Tyto informace jsou obsa- ženy ve výstupním textu generovaném preprocesorem, objevují se v chybových hlášeních - direktiva #lineumožňuje nastavit jméno souboru i číslo řádku tak, jak programátor potřebuje #line konstanta [jmeno_souboru] - konstanta - další číslo, které bude přiřazeno

  22. Preprocesor - je-li vynechán nepovinný parametr jmeno_souboru, platí napo- sledy nastavené direktivou line, resp. originální jméno souboru - v běžné programátorské praxi se používá ojediněle Generování chyb při překladu - slouží k zabránění určitých podmínek při překladu (nevhodný rozsah konstant, nevhodný překladač, nevhodný paměťový model, nevhodný operační systém, …) #error text - text je hlášení, které se objeví při překladu #define BUFFER 2000 #if BUFFER < 1000 … #error Buffer je prilis maly ifndef __LARGE__ #endif #error Nevhodny pametovy model #endif

  23. Preprocesor Pragmy - tato direktiva je mlhavě definovaná normou ANSI, pomocí ní se zapisují instrukce pro překladač závislé na implementaci #pragma jmeno_direktivy - jména direktiv mají být pro konkrétní překladač navržena tak, aby nedocházelo ke kolizím (pro každý překladač unikátní). Po- kud překladač narazí na direktivu pragma, jejíž název nezná, di- rektivu ignoruje aniž by generoval chybovou zprávu - direktiva pragma se většinou používá pro nastavení některých voleb překladače na úrovni zdrojového textu místo v parame- trech příkazového řádku #pragma argsused #pragma startup jmeno_fce priorita #pragma inline #pragma saveregs #pragma warn

More Related