LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (15) - Proměnné

V dnešním díle probereme podrobněji proměnné. Ukážeme si, jak se definují ukazatele na funkce a na co jsou dobré. Dojde na modifikátory proměnných a to i v souvislosti s projekty z více souborů.

23.2.2005 15:00 | Jan Němec | Články autora | přečteno 40618×

Funkce jako typ a proměnná

Funkci již umíme definovat a volat, umíme také deklarovat jejich hlavičky. Céčko navíc umožňuje definovat ukazatel na funkci. Jedná se skutečně o ukazatel do paměti, označuje místo v kódu, kde začíná přeložená funkce. S ukazatelem na funkci lze pracovat jako s běžnou proměnnou, můžeme do něj přiřadit nějakou hodnotu nebo jej předat jako parametr funkce, lze také vypsat jeho hodnotu. Pokud architektura umožňuje číst programu vlastní kód (běžně ano), můžeme ukazatel na funkci přetypovat na ukazatel na unsigned char a naučit se strojový kód. Pamětníci z dob MS-DOSu zavzpomínají i na sebemodifikaci spuštěného kódu, ale v chráněném módu na Linuxu podobné pokusy skončí špatně. Především však lze funkci, na niž ukazatel míří zavolat.

/* p je ukazatel na funkci s parametrem typu const char *
   a vracející int */
int (* p)(const char *);

/* Identifikátor funkce bez kulatých závorek znamená
   ukazatel na funkci */
p = puts;
printf("Funkce puts je v paměti na adrese %p.\n", (void *) p);
/* Ukazatel na puts lze normálně zavolat */
p("Ahoj světe!");

Nejsložitější na celém příkladu je určitě konstrukce typu ukazatele. Nejdřív se píše typ návratové hodnoty funkce, potom v kulatých závorkách hvězdička a identifikátor - jméno definovaného ukazatele a nakonec následují opět v kulatých závorkách typy parametrů funkce. Všimněte si, že název funkce je v C kódu pouze konstantní ukazatel na tuto funkci. Volání funkce přes ukazatel, definovaný jako proměnná, je už stejné, jako běžné volání funkce.

Ukazatele na funkce se nejčastěji používají v souvislosti s knihovnami, kdy je třeba nějakým dostatečně obecným způsobem parametrizovat algoritmus z knihovny. Pomocí ukazatele na funkci lze říci nějaké GUI knihovně, co se má stát při stisknutí tlačítka (zavolat uživatelskou funkci předanou jako parametr). Časově náročné funkce z knihoven občas umožní zadat jako parametr funkci, která se bude jednou za čas během výpočtu volat. Například programátor obecně užitečné knihovny na násobení velkých matic neví, jakým způsobem (a zda vůbec) informovat uživatele během výpočtu. To ví až aplikační programátor. Proto programátor knihovny přidá jako poslední parametr funkce na násobení matic ukazatel na funkci (tu už píše aplikační programátor), která se zavolá po vypočtení každého prvku výsledné matice. V grafické aplikaci se pak může pohybovat teploměr od 0% ke 100%, v interaktivním konzolovém programu se bude vypisovat na standardní výstup atd., ačkoli oba programy používají stejnou knihovnu.

#include <stdio.h>
/* Tohle je jako časově náročná funkce z knihovny */
void NapisStoTecek(void (* callback)(int)) {
  int i;

  for (i = 0; i < 100; i++) {
    /* Jednou za deset teček zavolej parametr */
    if (!(i % 10)) callback(i);
    /* Vypisuj tečky */
    putchar('.');
  }
}

/* Funkce volaná z knihovny, ale definovaná v aplikačním kódu */
void parametr(int procent) {
  printf("\nHotovo na %i%%\n", procent);
}

/* Hlavní program */
int main(void) {
  NapisStoTecek(parametr);
  return 0;
}

Modifikátory proměnných

Když nepočítáme parametry funkcí, zná Céčko dva druhy proměnných. Lokální, definované uvnitř funkce, a globální definované mimo funkci. Lokální proměnná má vyhrazené místo na zásobníku, a je tedy svázána nejen s konkrétní funkcí, ale přímo s její instancí. V případě rekurze tak pro každé volání funkce vzniknou i instance jejích lokálních proměnných a přiřazení do lokální proměnné proto ovlivní hodnotu pouze příslušné instance. Toto chování lze změnit klíčovým slovem static. Lokální proměnná definovaná jako static má vždy jen jednu instanci uloženou stejně jako globální proměnné, navíc její případná inicializace v definici proběhne jen jednou.

void funkce(void) {
  static int i = 0;

  printf("Celkový počet volání funkce = %i\n", ++i);
}

U globálních proměnných má static poněkud jiný význam. Jedná se o omezení platnosti proměnné na příslušný modul. Z ostatních souborů je pak tato proměnná nedostupná, jde tedy o jakousi ochranu identifikátorů podobně jako v případě static funkcí.

Globální proměnná z jiného zdrojového souboru se zpřístupní pomocí extern. Pokud v jednom souboru definujeme

int pocet;

můžeme tuto proměnnou používat z jiného souboru, pokud v něm deklarujeme

extern int pocet;

Jde tedy jen (podobně jako v případě hlaviček funkcí) o jakousi informaci pro překladač, že pocet je známý identifikátor, proměnná typu int, která je definovaná někde jinde. Pokud v celém projektu není nikde definovaná bez extern, ale je používaná, projde vlastní překlad jednotlivých souborů, ale při linkování dojde k chybě.

Pokud nám záleží na efektivitě programu, můžeme označit lokální proměnnou jako register.

void funkce(void) {
  register int i;
  /* ... */
}

Je to doporučení pro překladač, aby umístil tuto proměnnou do registru procesoru a nikoli na zásobník. Práce s registry je pochopitelně podstatně rychlejší. Překladač může toto doporučení ignorovat (u dnešních překladačů běžné) a může také proměnnou dát do registru sám od sebe (i to je obvyklé). Označení register má tedy smysl pro dobrovolně spolupracující překladače se špatnou optimalizací, například staré dosovské verze Borland C++.

Překladač se obvykle pokouší kód zjednodušit tak, aby na cílovém procesoru běžel co nejrychleji. V tom mu podstatně pomáhá znalost hodnot proměnných, například po

i = 5;

může předpokládat, že v proměnné i bude skutečně hodnota 5 a to až do nějakého příkazu, který to může změnit. Problém nastane u programů s obsluhou asynchronních událostí (signály) nebo více vlákny. Cyklus

int i = 0;

while (!i);

tj. čekej, dokud signál nebo jiné vlákno nezmění hodnotu i, smí překladač "vyoptimalizovat" na

while (1);

tj. čekej do nekonečna. Z tohoto důvodu existuje modifikátor volatile, který překladači zakazuje provádět jakékoli předpoklady o hodnotě proměnné.

volatile int i = 0;

while (!i);

Teď je příklad správný, pouze poněkud neefektivní, neboť aktivní čekání zbytečně vytíží procesor.

Modifikátor const již známe. Jde o označení proměnných, které nelze jednoduchým způsobem měnit. Nejedná se však o skutečné konstanty, neboť je nelze použít např. při definici mezí polí. Tento modifikátor je rozumné použít zejména u vstupních parametrů funkce předávaných pomocí ukazatelů. Je-li parametrem funkce const char *, je zřejmé, že funkce nemá v úmyslu řetězec měnit. Užití const tak zvyšuje čitelnost programu.

Pokračování příště

V příštím dílu se naučíme psát hlavičkové soubory.

Verze pro tisk

pridej.cz

 

DISKUZE

Pokračování......... ??? 4.3.2005 11:43 Herfik
  L Re: Pokračování......... ??? 4.3.2005 15:45 Jan Němec




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

18.9.2018 23:30 /František Kučera

Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.


Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

18.6.2018 0:43 /František Kučera
Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.
Přidat komentář

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2018) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze