Použití příkazu GOTO v jazyku C

gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
Re:Použití příkazu GOTO v jazyku C
« Odpověď #30 kdy: 20. 08. 2019, 13:13:55 »
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Sice je to špatný příklad, kde by nemělo pro pár instrukcí smysl dělat nějakou optimalizaci...
Ale co je špatného na tomto:
Kód: [Vybrat]
err = a_init();
if (err) return err;
err = b_init();
if (err) return err;
err = c_init();
if (err) return err;
?

musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.


Re:Použití příkazu GOTO v jazyku C
« Odpověď #31 kdy: 20. 08. 2019, 13:19:56 »
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.

Re:Použití příkazu GOTO v jazyku C
« Odpověď #32 kdy: 20. 08. 2019, 13:57:27 »
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?

Re:Použití příkazu GOTO v jazyku C
« Odpověď #33 kdy: 20. 08. 2019, 14:18:00 »
Snad nikdy sem nevidel kod, kde by bylo GOTO nejak zneuzivano. IMO se cele GOTO trochu moc demonizuje. Pouziva se minimalne a kdyz uz, tak to na tom miste, kde se pouzilo, proste nevadi. Ucit deti, ze by GOTO nemely pouzivat asi nejaky smysl ma, ale obecne, kdyz nekdo zacne programovat a misto "BEGIN" a "END" si vybere GOTO, asi by se mel radeji venovat necemu jinemu.

gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
Re:Použití příkazu GOTO v jazyku C
« Odpověď #34 kdy: 20. 08. 2019, 14:46:44 »
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,

myslel jsem, že se tu řeší, jak se takovým konstruktům vyhnout pomocí GOTO.


Re:Použití příkazu GOTO v jazyku C
« Odpověď #35 kdy: 20. 08. 2019, 15:05:53 »
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,

myslel jsem, že se tu řeší, jak se takovým konstruktům vyhnout pomocí GOTO.
Dobře, záleží, jestli hledáme argumenty pro použití goto, nebo proti.

Re:Použití příkazu GOTO v jazyku C
« Odpověď #36 kdy: 20. 08. 2019, 22:12:05 »
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
To si můžete dovolit tam, kde nepotřebujete před návratem provést nějaký úklid. Samozřejmě jde použít i něco jako
Kód: [Vybrat]
        ret = init_foo();
        if (ret < 0) {
                /* cleanup */
                return ret;
        }
ale v případech, o kterých se tu bavíme, bude toho úklidu přibývat, jak bude přibývat provedených inicializací.
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Zkuste se podívat třeba sem na funkci inet6_init() a rozmyslete si, jak by ten kód vypadal, kdybyste se chtěl za každou cenu vyhnout použití goto.

Re:Použití příkazu GOTO v jazyku C
« Odpověď #37 kdy: 20. 08. 2019, 22:20:12 »
Citace
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě). Pokud tedy vynecháte některé z finit volání, tak máte pravděpodobně resource leak.

Samozřejmě, můžete si pamatovat , že "když funkce X selže, musím někde zavolat a_finit, protože ona to neudělala"; podle mě pak ale kód přestává být srozumitelný.

Re:Použití příkazu GOTO v jazyku C
« Odpověď #38 kdy: 20. 08. 2019, 23:38:52 »
Citace
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě).

No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).

Re:Použití příkazu GOTO v jazyku C
« Odpověď #39 kdy: 21. 08. 2019, 05:41:08 »
Samozřejmě, můžete si pamatovat , že "když funkce X selže, musím někde zavolat a_finit, protože ona to neudělala"; podle mě pak ale kód přestává být srozumitelný.
Hlavně rychle přestane být udržovatelný. Bude potřeba pořád hlídat, jestli na to někdo nezapomněl. Když se bude volat na deseti místech, tak aby si na to člověk radši napsal wrapper - ale když tu funkci budu pokaždé volat přes (stejný) wrapper, tím spíš vynikne, že cleanup měl být rovnou v té funkci. A ani z logického hlediska to nedává smysl, pokud funkce něco alokuje, má to po návratu zůstat alokované jen v případě, že volající potřebuje, aby to alokované zůstalo.

Navíc jsme se tu bavili o případech, kdy těch inicializačních kroků je víc, selhat může kterýkoli z nich a volající obecně neví, který to byl a co je potřeba uklidit. Nemluvě o tom, že v praxi to často nebude jen prosté a_init() ... a_finit(), protože se úklidové funkci bude předávat pointer na to, co se má uklidit, který volající ani nebude mít k dispozici.

nula

Re:Použití příkazu GOTO v jazyku C
« Odpověď #40 kdy: 21. 08. 2019, 07:53:41 »
:D compilace/disassembling je docela dobry napad  :)

Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.

https://godbolt.org/z/elNcJ8 - to je dobry link, diky moc  :)

To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.

Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )

Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?

A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

Jo jasne, je lepsi se vyhybat ifum, ale pattern matching je cesta... haha, tak ty jsi to rozsekl frajere...
Co je spatneho na pattern matching?

Za mne vubec nic, ale ja taky neplivu na ify. Mi prijde vtipne, ze plives na obecne vyhodnocovani podminky, ale  vyhodnocovani konkretni podminky a to konkretne pattern matchingu ti prijde v poradku.

nula

Re:Použití příkazu GOTO v jazyku C
« Odpověď #41 kdy: 21. 08. 2019, 07:57:03 »
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Sice je to špatný příklad, kde by nemělo pro pár instrukcí smysl dělat nějakou optimalizaci...
Ale co je špatného na tomto:
Kód: [Vybrat]
err = a_init();
if (err) return err;
err = b_init();
if (err) return err;
err = c_init();
if (err) return err;
?

Kde a jak zavolate a_finit(), b_finit(), atd. ?

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Použití příkazu GOTO v jazyku C
« Odpověď #42 kdy: 21. 08. 2019, 09:15:58 »
Citace
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě).

No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).
Můžou měnit kontext.

Re:Použití příkazu GOTO v jazyku C
« Odpověď #43 kdy: 21. 08. 2019, 09:49:43 »
Nejznámější variantou goto je switch-case. Jinak v C++ je to složitější když v rámci skoku preskakuju inicializaci objektů - není to fakt dobrý nápad a týká se to i switch case. Naštěstí překladač to oznámí. Takže je fakt dobré sahat na goto až je to opravdu nutné

Pokud při skoku opouštím blok kde končí platnost některých proměnných, zavolají se destruktory - takže obyčejný JMP to není.

(Právě kvůli finalizaci mám rád koncept RAII - pak goto nepotřebuju)

Re:Použití příkazu GOTO v jazyku C
« Odpověď #44 kdy: 13. 10. 2019, 08:00:18 »
> povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny?

Co to pro vás znamená?  Pokud vyskočíte ze scope, tak jste vyskočil ze scope.  A pokud nepoužíváte nějaké GNU extensions jako je __attribute__((cleanup(...))), tak opuštění scope v C nic moc neznamená.