View
44
Download
0
Category
Preview:
DESCRIPTION
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 - PowerPoint PPT Presentation
Citation preview
8. přednáška27. 3. 2008
-typedef- preprocesor
Studijní materiály najdete na adrese:
http://www.uai.fme.vutbr.cz/~vdumek/
- 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
- 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 intint *f2(); intuk f2(); fce vracející ukazatel na
inttypedef int far *faruk;
int far *u2; faruk u2; vzdálený ukazatel na intint far *f3(); faruk f3(); funkce vracející vzdálený
ukazatel na inttypedef int (*fnuk1)(int);
int (*fu1)(int); fnuk1 fu1; ukazatel na fci s jedním intparametrem, 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
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ů
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
#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
- 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
#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 radekstala se nejaka jina chybastala se nejaka chyba
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ě
- 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
- 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 */
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); */
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 */
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
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 */
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
Preprocesor
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 */
#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
- 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
#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 */
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 #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
- 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 malyifndef __LARGE__ #endif#error Nevhodny pametovy model#endif
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
Preprocesor
Recommended