Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze – Lekce 4 - Makra v jazyce C

Zpět

Upozorňujeme, že diskuze pod našimi online kurzy jsou nemoderované a primárně slouží k získávání zpětné vazby pro budoucí vylepšení kurzů. Pro studenty našich rekvalifikačních kurzů nabízíme možnost přímého kontaktu s lektory a studijním referentem pro osobní konzultace a podporu v rámci jejich studia. Toto je exkluzivní služba, která zajišťuje kvalitní a cílenou pomoc v případě jakýchkoli dotazů nebo projektů.

Komentáře
Avatar
coells
Tvůrce
Avatar
Odpovídá na SPoon
coells:11.8.2014 9:44

Požadavek "neodkazovat se pomocí pointeru" nelze brát v úvahu, jsme v C. Na proměnnou j se nikdy nemusím odkázat a stejně vím, kde je a mám na ni pointer (v tom lepším případě, v tom horším mám pouze pointer).

const int i = 1;
const int j = 2;

int *pj = &i + 1;

Klíčová věc je, jak je konstanta definovaná a kde bude uložená. Díky tomu, jsem clang donutil chovat se pokaždé jinak, stále je to ale deterministické chování.

Naprosto klíčová věc jsou ale optimalizace. A tady je kámen úrazu a důvod, proč je takový kód nekorektní. Vygenerovaný kód se bude chovat odlišně v závislosti na typu optimalizace a dokonce i zařízení, na kterém poběží. Jedny z nejtěžších chyb, které občas musím hledat, jsou pády aplikace, která skvěle běží v simulátoru na core i7, ale na armv7 "bezdůvodně" padá. Na tom není nic nedeterministic­kého, stačí vědět, co se děje na úrovni kompilátoru.

 
Odpovědět
11.8.2014 9:44
Avatar
SPoon
Tvůrce
Avatar
Odpovídá na coells
SPoon:11.8.2014 10:01

Špatně jsem se vyjádřil. Myslel jsem tím, že pokud se kdekoli v kódu objeví tento řádek z tvého příkladu, tak i při zapnutých optimalizacích bude konstanta umístěna v paměti, protože se už pracuje s její adresou.

int *pj = &i + 1;

Pokud se konstanta použije například jenom v operaci přiřazení nebo porovnání, tak se při zapnutých optimalizacích nemusí v paměti objevit vůbec a je v kódu přímo nahrazena její hodnotou.

 
Odpovědět
11.8.2014 10:01
Avatar
pracansky
Člen
Avatar
pracansky:29.4.2015 21:27

Doporučený zápis na začátku článku ve skutečnosti není úplně bezpečný.

// správný zápis
#define SQR(a) (a)*(a)

Uvedu to na jednoduchém příkladu

#define Secti(a,b)  (a)+(b)
int x = 2 * Secti(2,2);

Na první pohled by se zdálo že Secti vrátí hodnotu 4 a po vynásobení dvěma bude výsledek 8.
Makro se ale rozbalí na:

int x = 2 * (2) + (2);

takže výsledek bude 6.
Makra toho typu by se **vždy **měla závorkovat takto

#define Secti(a,b) ((a)+(b))
 
Odpovědět
29.4.2015 21:27
Avatar
Odpovídá na SPoon
Patrik Pastor:4.9.2019 18:23

a proc vadi ze se zapise constanta do pameti (v pripade ze se na ni &promenna referencujes)? To zabira tolik mista? Nebo je to nebezpecne ze strany kompilatory, jak si s tim poradi? To ze je constanta, by melo znamenat, za by se nemela dat zmenit hodnota teto promenne. Ale stale prece muzes mit na ni ukazatel, kdyz je to stale promenna, jako kazda jina (jestli to spravne rozumim). Nebo co presne vadi kompilatoru na tom, ze se pokousis referencovat uzakatelem na adresu constanty

 
Odpovědět
4.9.2019 18:23
Avatar
Patrik Pastor:4.9.2019 18:25

Proc se vlastne u guardu definuje jmeno (nazev)?

#ifndef NAZEV
#define NAZEV

kdyz stejne nento nazev nebudu pri includovani tohoto souboru pouzivat, ale budu pouzivate nazev vlastniho souboru. Proc ma ale samotny guard svuj nazev? to ho muzu jeste nekde jinde pouzit

 
Odpovědět
4.9.2019 18:25
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Patrik Pastor
DarkCoder:4.9.2019 19:50

V článku to je popsané, odstavec "Include guard". Celá tato konstrukce:

#ifndef JMENO_MAKRA
#define JMENO_MAKRA
...

#endif

má za úkol nedovolit vložit obsah souboru do programu více než jednou. Např. definice typů, které bývají obsahem hlavičkových souborů, nelze do programu vložit více než jednou. Program se nepovede přeložit. Celé to funguje tak, že při prvním pokusu o přeložení se otestuje existence makra. Jelikož makro neexistuje, vloží se celý obsah souboru do programu a zároveň se definuje makro. Při druhém pokusu nedojde k opětovnému vložení, protože makro už existuje a test na jeho neexistenci se vyhodnotí jako nepravdivá a nedojde tak k vložení obsahu souboru do programu. Pokud makro nedefinuješ, test podmínky projde a dojde k vícero vložení obsahu souboru což způsobí při překladu chybu.

Odpovědět
4.9.2019 19:50
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Nositelka Změny:5.1.2020 15:50

Je pravda, že dnes již není potřeba psát inline a dnešní kompilátory si ho tam dopíší samy, pokud to bude vhodné? Podobně jako existovaly modifikátory auto a register, kterými programátor určil, zda se proměnná má uložit do registru nebo na zásobník. Dnes to již není potřeba a kompilátor si to zařídí sám. I když tato klíčová slova použijeme, kompilátor je může klidně ignorovat. Může ignorovat i inline, když se nehodí. Ale nejsem si jistý, zda může krátkou funkci použít jako inline, i když ji tak neoznačíme. Vím jen, že to je možné - v Javě to funguje, ale jestli i C? …

Odpovědět
5.1.2020 15:50
j.k.j
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Nositelka Změny
DarkCoder:5.1.2020 17:13

Ne. Klíčové slovo inline, přidané v C99, není automaticky k funkci doplňováno překladačem. Je to pouze doporučení pro překladač. Začlenění modifikované funkce pomocí klíčového slova inline ještě neznamená, že funkce bude napřímo vložena. Vložení funkce má jistá pravidla, která překladač vyhodnocuje a na jejich základě se rozhodne, zda-li modifikovanou funkci do programu začlení.

Klíčové slovo auto, které existuje dodnes, se vesměs nepoužívá. Každá lokální proměnná je obecně deklarována jako auto. Toto klíčové slovo do jazyka C bylo přidáno kvůli kompatibilitě s jazykem B.

U klíčového slova register nedochází k automatickému uložení proměnné do registru. Je to opět instrukce pro překladač, že má k proměnné přistupovat pokud možno co nejrychleji. Register je stále nejlepší volba. Dále automatické uložení proměnné modifikované klíčovým slovem register do registru nemusí proběhnout z důvodu omezeného počtu registrových proměnných.

Tedy vkládání těchto klíčových slov před funkce respektive před proměnné má svůj význam, neprobíhá to ani automaticky ani zaručeně. Záleží také na druhu optimalizace a na tom zda je optimalizace vůbec povolena.

Odpovědět
5.1.2020 17:13
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Nositelka Změny:5.1.2020 18:24

Tak trochu jsem se toho obávala - takže psát inline má smysl i dnes. Ale podle linuxsoftu je použití register při dnešní optimalizaci zbytečné (předpokládám, že tehdejší dnešní na tom není jinak než dnešní dnešní, proč by se zrovna tohle mělo měnit, když optimalizace lze vypnout). O auto vím jenom díky jednomu seznamu klíčových slov C, najít jeho význam bylo složitější. Na žádném českém webu se o tom nemluví, ale v angličtině je toho dost. Díky za vysvětlení.

Odpovědět
5.1.2020 18:24
j.k.j
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Nositelka Změny
DarkCoder:5.1.2020 19:07

Není třeba se toho obávat, na funkčnost kódu to vliv nemá. Použití inline má velký smysl. Dokáže zrychlit provádění programu. To proč není automaticky použito pro každou funkci je to, že nemá jen výhody. Začlenění funkce přímo do programu ovlivňuje velikost programu. Takže je dobré si promyslet, kde to smysl má a kde ne. Než přišla norma C99, používala se především makra s parametry. Tato makra si vyžadovala a stále vyžadují správné použití závorek. Jejich absence může mít vliv (a dost často má) na funkci makra. Od C99 bylo vesměs použití parametrizovaných maker nahrazeno mnohem jednodušším způsobem za pomocí klíčového slova inline.

Kdyby měla optimalizace jedno kritérium, pak by tomu tak bylo. Ale jelikož jich je více, je použití klíčového slova registr stále aktuální. Počet proměnných může být hodně velké a počet registrovaných proměnných je omezen. Když budu chtít optimalizovat svůj program, těžko překladač bude vědět jak to chci já. Bude optimalizovat ty proměnné které se v programu vyskytují nejčastěji nebo mi optimalizuje ty, kde část kódu trvá nejdéle? Nebo bude pro mě kritická jiná oblast, kterou překladač nerozpozná.

Jak už jsem psal, modifikátor auto se už dnes nepoužívá, ale lze ho spatřit v mnoha starších programech. Je tedy dobré vědět, že něco takového existuje a nebýt tak překvapen.

Odpovědět
5.1.2020 19:07
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 20.