Stáhnout prezentaci
Prezentace se nahrává, počkejte prosím
ZveřejnilAlexander Kučera
1
8. přednáška 27. 3. 2008 -typedef - preprocesor Studijní materiály najdete na adrese: http://www.uai.fme.vutbr.cz/~vdumek/
2
- 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 */ Typedef
3
- 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 Typedef
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.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: void main(void) { // komentar #define DESET 10 #define SYMBOL if(DESET == 9) printf("ahoj"); /* dalsi komentar */ } test.c test.i CPP
6
#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 Preprocesor
7
- 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 Preprocesor
8
#include #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
- 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 Preprocesor
11
- 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 VLOZENIse rozvine jako #include /* chyba */ Preprocesor
12
- 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); */ Preprocesor
13
- 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 */ Preprocesor
14
#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 #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 Preprocesor
15
S1.CS2.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 */ Preprocesor
16
- 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 Preprocesor
17
- ú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
- 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 Preprocesor
20
#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 100) */ #endif /* ukončení podmínky Y>100 */ ….. #endif/* ukončení podmínky X<25 */ Preprocesor
21
- 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 #line umožň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 Preprocesor
22
- 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 Preprocesor
23
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 Preprocesor
Podobné prezentace
© 2024 SlidePlayer.cz Inc.
All rights reserved.