Variables ve funkcích

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
zbysek
Site Admin
Příspěvky: 125
Registrován: 22 úno 2017, 15:18
Reputation: 0

Re: Variables ve funkcích

Příspěvek od zbysek » 05 říj 2019, 18:51

Ono s těmi globálními proměnnými je to trochu komplikované.

Úplně se jim nevyhneme asi nikdy (alespoň v C/C++), protože ve většině programů, které nejsou jen nějaké jednoduché ukázky, potřebujeme někde držet stav. Na druhou stranu by se to s nimi nemělo přehánět. Také není moc dobré do funkcí zanášet vedlejší efekty (měnit stav globálních proměnných apod.), protože ty občas vedou na špatně hledatelné chyby. Ideální je data pro funkci dostat z parametrů a pak třeba nový stav z funkce vrátit (a dosáhnout tak čistých funkcí).

A pak tu máme svět vestavných zařízení, kde spousta pouček pro "moderní programování" neplatí. Moc malých funkcí (často vzešlých z refactoringu) zpomaluje program (protože každé volání funkce má určitou režii), parametry funkcí ho zpomalují také (protože se musí ukládat na zásobník). Takže ty globální proměnné možná nejsou zas tak špatná cesta, pokud je používáme s rozvahou.

A tyhle detaily jsou na tom tak pěkné... :)

KamilV
Příspěvky: 479
Registrován: 03 dub 2018, 15:27
Reputation: 0
Bydliště: Olomouc

Re: Variables ve funkcích

Příspěvek od KamilV » 08 říj 2019, 09:32

Udržovat stavy se mohou i v atributech konkrétní třídy. Narozdíl od globálu jsou takové atributy "tématicky rozškatulkované", snadněji dohledatelné a kontrolovatelné (do globálu může zapsat kdokoliv cokoliv a kdekoliv).

Ovšem velmi zajímavý je pohled z hlediska maximalizace výkonu. Celé to asi tedy vede k tomu, že by měly být 2 "best practice": když potřebuju maximální výkon na mikrosekundy a když ne.

Pak také záleží na velikosti projektu. Pokud je to jeden soubor o 10 funkcích, tak to člověk snadno ukočíruje i s globály. Když už je to třeba 10 souborů, je člověk rád, že každý je tvořen vlastní třídou a své stavy si udržuje uvnitř sebe sama, i za cenu, že výpočet stojí nějakou mikrosekundu navíc (asi ani tolik ne).

Zajímavý by byl nějaký test nebo příklad, kdy někdo narazil na to, že ho zdržovalo volání funkcí s parametrem, neměl bys k tomu něco?

Uživatelský avatar
gilhad
Příspěvky: 779
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Variables ve funkcích

Příspěvek od gilhad » 08 říj 2019, 13:10

O programech se rika - rychlost, velikost, prehlednost - vyber si libovolne 2. V pripade maximalizace pak vyber pouze 1.

U Arduina vyber za vas provedli jeho autori a zvolili prehlednost (ac to tak na tomto foru leckdy nevypada).

Napriklad digitalRead jde napsat na 3 ASM instrukce (2, pokud chcete cist vsech 8 pinu daneho portu), nebo asi na 100, pokud pouzivate Arduino - neni to usporne ani na rychlost, ani na pamet (samotne volani stoji vic, nez by stala dotycna operace). A to je jedna z usporneji implenetovanych veci.

Pokud bys potreboval optimalizovat rychlost, nebo velikost, tak zacnes tim, ze to napises v Ccku, bez pouziti Wiringu a ostatnich knihoven, co obali vsechna volani tunou vaty (obcas i chybne) a skryjou obsah pred programatorem. Pokud by ti to nestacilo, tak zoptimalizujes vygenerovany ASM rucne. Pokud by nestacilo ani to, tak to napises v ASM rovnou s pouzitim vsech moznosti procesoru.

Co se volani funkci s parametrem tyce, jakmile bys mel predavat nejakou vetsi strukturu, tak bud odkazem (nebo adresou), nebo jako globalni promennou, podle okolnosti. Pokud ma funkce milion parametru, tak je to asi taky neoptimalni. Objekty jsou prehledne, ale maji rezii navic, zvlast pokud deklarujes vsechny funkce jako virtualni a pouzijes kosatejsi strom dedeni, nez je nutne. V embeded systemech je vetsinou vhodne se vyhnout dynamickemu alokovani a dealokovani pameti (coz se obzvlast tyce vytvareni a ruseni spousty objektu). Pouzivani konstantnich retezcu bez PROG atributu je obvykle plytvani RAM, pouzivani String obvykle take.

Kvalita knihoven okolo Arduina je tradicne prinejmensim pochybna, misty zoufala (a navic je znacna cast z toho by_design aby se uzivatel nedozvedel, co vlastne dela a nezdesil se, ze jde o programovani). Ale blikani LEDkou se z toho da slepit rychle, aniz by dotycny musel umet programovat. (Nez zacnete optimalizovat, naucte se programovat. Ne, Arduino k tomu rozhodne nenabada a nevede. A lepeni kusu kodu z internetu, v nadeji, ze to treba neco udela uz vubec ne. Naucte se C, pak se podivejte na C++ a uvedomte si, ze spoustu z toho muselo byt na embeded strojich zase obetovano, protoze by se to ani neveslo do pameti, takze na klasicke frameworky zapomente a zjistete si, co tu skutecne je a z toho pouzivejte to, co skutecne doopravdy potrebujete.)

Co se globalnich promennych tyce - pokud mate nekde v programu Wire, nebo Serial, tak je pouzivate, Arduino se stara za vas, aby byly globalni a vsude dostupne. Stejne jako rada dalsich, vetsina knihoven si nejakou/nejake zavede sama o sobe, takze pouzitim knihovny pribude obvykle hrst globalu taky.

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Variables ve funkcích

Příspěvek od kiRRow » 08 říj 2019, 16:16

Globální proměnné mám rád jako sůl :D

ps : ... hlavně přiměřeně :)

Uživatelský avatar
gilhad
Příspěvky: 779
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Variables ve funkcích

Příspěvek od gilhad » 08 říj 2019, 17:31

Na druhou stranu by se patrilo dodat a ZDURAZNIT, ze predcasna optimalizace je korenem vseho zla. (A nevhodna optimalizazce taky.)

Takze pokud se vam na Arduinu vejde program do flasky, tak je NAPROSTO ZBYTECNE ho optimalizovat na velikost, protoze v te flasce uz nic jineho nebude a co nepouzije program, to bude proste lezet ladem a neprinese zadny uzitek.

Dokud vam nechodi spravne a spolehlive, tak nema cenu ho optimalizovat na rychlost a vetsinou ani na obsazenou RAM (pokud to kvuli ni nepada jeste pred vyskytem prvni chyby), ale naopak je treba ho optimalizovat na citelnost a spravnou funkci.

Komentare a spravne odsazeni se pri prekladu odfitrujou a nestoji to na vykonu nic. (Ten zlomek sekundy pri prekladu je smesny v porovnani s dobou prekladu vsech tech knihoven okolo.) Na druhou stranu vam usetri ne minuty, ale obvykle hodiny a dny pri psani a ladeni programu. Rozumnych komentaru neni nikdy moc.

Existuji aplikace, kde 10 instrukci spalenych na volani interruptu hraje roli. Volani funkce stoji obvykle jeste vic, pouziti parametru misto globalni promenne vas prijde asi na 4 takty pri volani funkce a 1-2 takty pri pouziti. Pouziti int misto byte vas prijde asi na 4 nasobek taktu pri kazdem pouziti, stejne tal pouziti long misto int.
Jedine zavolani delay(1) vas prijde na 16.0000 taktu.

Pokud uz potrebujete optimalizovat, optimalizujte vzdy tam, kde to ma nejvetsi efekt. (Coz vetsinou znamena profilovani, nebo dukladnou analyzu, nebo aspon nejake logy - ktere samy taky zdaleka nejsou zdarma).

Naopak pouzit dlouhych_a_popisnych_jmen_promennych oproti x,_x,x1 a x2 nestoji vubec nic - prekladac je stejne nahradi adresama - tudiz pouzivejte dlouhe a popisne jmena - pri preklepu z x na c vam prekladac nic nerekne, pokud obe existuji. Pri preklepu v dlouhem jmene je miziva sance, ze byste trefili neco jineho a tudiz se chyba odhali pri prvnim pokusu o preklad.

Pokud sem pisete z prohlizece mladsiho 5 let, tak vas vliv na dobu prekladu a potrebna pamet pro nej NEZAJIMA - jedina chyba ci oprava vam ztrati radove vic casu, nez libovolna uspora dosazitelna v programu. (A nutno dodat, ze vetsinu z toho casu stravite v editoru a pri premysleni, nikoli prekladem)

Pokud vas prece jen trapi vykon vasi aplikace a vejdete se do pameti (predpokladam, ze vsech delay() jste se zbavili uz davno), tak se zamyslete nad pouzitym algoritmem - spatny algoritmus klidne prodlouzi vypocty o nekolik (ci mnoho) radu, o minuty, dny, roky ...

Pokud je algoritmus efektivni a porad to jeste nestaci, omezte zbytecne volani knihovnich funkci (cili vseho co je v Arduinu "tak nejak samo"), daji se tim dosahnout dalsi radove uspory - misto nastavovani hodnoty LED pri kazdem pruchodu smyckou ji nastavujte jen kdyz se skutecne meni (a zapamatujte si, v jakem je stavu, at na to nemusite pouzivat pomaly a komplikovany digitalRead)

A projdete si, co delaji knihovny (zvlast, pokud je pouzivate i na jednoduche veci jako tlacitka, nikoli jen na ty slozite jako wifi ci ethernet).

A (nejen ladici) vypisy udelejte strucne, ale vystizne (kdo z vas vi, ze Serial si nastavuje vnitrni buffer v zavislosti na tom, kolik mate volne RAM - takze ma bud 32, nebo 64 byte - a ze pokud odeslete "naraz" min znaku, tak to volani neni blokujici a vypocet pokracuje, zatimco pokud poslete byt jen o znak vic (tedy 32+/64+, vcetne enteru a pod), tak se to zastavi, dokud se toho neodvysila dost - coz taky muze trvat)

A samozrejme je pak (kdyz musime setrit) lepsi udelat serii

Kód: Vybrat vše

Serial.write("x=");
Serial.write( x );
Serial.write(";y=");
Serial.write(  y );
Serial.write(";val=");
Serial.println( hodnota_mereni );
nez

Kód: Vybrat vše

String msg= "x=";  // String je objekt
msg += x + ";y=" + y + ";val=" + hodnota_mereni; // a tady jich udelame spoustu a dynamicky alokujeme pamet, abychom ji zase uvolnovali
Serial.println(msg);
protoze ta serie nevysiluje s objekty a je uspornejsi jak na pamet, tak na vypocty, zatimco druha metoda je zase o neco prehlednejsi, ale narocnejsi

A z vice ruznych duvodu (a Serial je jednim z nich) je vyhodnejsi udelat loop() ktera probehne co nejrychleji, nez v ni zdrzovat necim, co by se dalo rozhodit do vic pruchodu (viz blikame bez delay, nebo http://micro-corner.gilhad.cz/blog/Ardu ... ouse2.html kde mam velmi rychly stavovy automat )

Uživatelský avatar
gilhad
Příspěvky: 779
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Variables ve funkcích

Příspěvek od gilhad » 08 říj 2019, 17:36

kiRRow píše:
08 říj 2019, 16:16
Globální proměnné mám rád jako sůl :D

ps : ... hlavně přiměřeně :)
hlavne primerene :lol:

ony globaly jsou rychlejsi na pristup, ale strasi v pameti furt.

Pokud nas tlaci velikost RAM (a ani PROGMEM uz neni na co aplikovat) tak lokalni promenne ve funkcich, scopech (a zejmena v cyklech) jsou uspornejsi, protoze se snadno vytvareji na zasobniku a stejne snadno uvolnuji, takze pokud jde za sebou rada fukci ci scopu, tak to jedno misto muze byt pouzito bez rizika opakovane

Uživatelský avatar
gilhad
Příspěvky: 779
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Variables ve funkcích

Příspěvek od gilhad » 08 říj 2019, 17:43

Mimochodem existuje rada zpusobu, od jednoduchych az po silne obskurni, jak vyhandlovat kus RAM za kus FLASH ci naopak (a zdaleka to neni 1:1) a nektere dokonce muzou nejaky program docela urychlit, jine zase velmi zpomalit - ale pokud je FLASH, nebo RAM uzke hrdlo a rychlost neni, tak se muze hodit je pouzit. Nebo naopak, pokud je rychlost kriticka a je dost RAM/FLASH, tak ze da vyhandlovat kus pameti za urychleni.

A samozrejme znalost HW muze vyrazne pomoct pri optimalizaci na cokoli. A znalost interruptu (a casovacu) taky muze program pri spravnem pouziti nejen zrychlit, ale i vyrazne zjednodusit a zprehlednit.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Variables ve funkcích

Příspěvek od ondraN » 09 říj 2019, 17:51

Naprosto souhlasím s gilhadem. Osobně si myslím, že i používání objektů v běžném strukturovaném jazyce, je píše taková móda, než opodstatněná záležitost. Objekty se hodí spíše do plně objektových jazyků a vyžadují úplně jinou strukturu programu, aby byly efektivní. Pokud něco píšu, tak se držím raději ansi C a objekty používám pouze, pokud jsou v knihovnách a nemám chuť si to psát znovu. Céčko mi přijde dostatečně mocný nástroj pro mikrokontroléry (hlavně ty s menší pamětí RAM), že mi nějak uniká snaha tam objekty cpát. Jiná je,samozřejmě, situace na PC, ale to je úplně jiná kapitola.

Uživatelský avatar
gilhad
Příspěvky: 779
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Variables ve funkcích

Příspěvek od gilhad » 09 říj 2019, 21:52

No, objekty si s sebou nesou jak data, tak funkce pro praci s nimi a dobre pouzite to naopak mohou silne zjednodusit - coz mi pripomina, ze bych mel dokoncit http://micro-corner.gilhad.cz/blog/Ardu ... ouse3.html kde prave objekty s vyhodou pouzivam pro jednoduche stavove automaty (typicke pro mikrokontrolery - napriklad velmi pouzivane zpracovani komunikacnich protokolu) a bez objektu by to bylo vyrazne slozitejsi a nachylnejsi k chybam - zrovna tam bych ty objekty pouzil i pri programovani v assembleru, ktery je nepodporuje explicitne vubec, ale index do tabulky odkazu na sady fukci a dat se v nem jako kocept pouziva uz od pradavna (konec koncu co jineho je obsluha preruseni, ze) :)

Tady jsem v prispevku o setreni zdroji pouzil ten String jako ukazku toho, co si mnozi primo neuvedomi - ze misto pouziti retezcu znaku (char[]) to v tom prehlednejsim pripade na pozadi vytvari radu objektu typu String, aby je to vzapeti zase zrusilo.

KamilV
Příspěvky: 479
Registrován: 03 dub 2018, 15:27
Reputation: 0
Bydliště: Olomouc

Re: Variables ve funkcích

Příspěvek od KamilV » 09 říj 2019, 22:59

ondraN píše:
09 říj 2019, 17:51
Osobně si myslím, že i používání objektů v běžném strukturovaném jazyce, je píše taková móda, než opodstatněná záležitost.
Tohle si nemyslím, bohužel netuším, jak dalece jsi v OOP zběhlý, takže Ti samozřejmě nechci křivdit, jen už jsem se s podobnými hodnoceními setkal i u lidí, kteří objekty považují jen za "obálky pro funkce". Síla OOP je samozřejmě jinde. A ano, stojí to nějakou režii a programátor musí určit, co je v daný moment větším přínosem. Ale odpálit to šmahem, že je to jen něco módního, se mi zdá příkré...

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 9 hostů