GNU/Linux >> Znalost Linux >  >> Linux

Proč fclose(NULL) glibc způsobí chybu segmentace místo vracení chyby?

fclose vyžaduje jako argument FILE ukazatel získaný buď pomocí fopen , jeden ze standardních streamů stdin , stdout nebo stderr nebo jiným způsobem definovaným implementací. Nulový ukazatel není jedním z nich, takže chování není definováno, stejně jako fclose((FILE *)0xdeadbeef) bylo by. NULL není zvláštní v C; kromě skutečnosti, že je zaručeno, že se nerovná žádnému platnému ukazateli, je jako jakýkoli jiný neplatný ukazatel a jeho použití vyvolává nedefinované chování, kromě případů, kdy rozhraní, které předáváte dokumentům jako součást jeho smlouvy, že NULL má nějaký zvláštní význam.

Dále by návrat s chybou byl platný (protože chování stejně není definováno), ale škodlivé chování pro implementaci, protože skryje nedefinované chování . Preferovaným výsledkem vyvolání nedefinovaného chování je vždy selhání, protože zvýrazní chybu a umožní vám ji opravit. Většina uživatelů fclose nekontrolujte návratovou hodnotu chyby a vsadil bych se, že většina lidí je natolik hloupá, že překročí NULL na fclose nebudou dostatečně inteligentní, aby zkontrolovali návratovou hodnotu fclose . Dalo by se uvést, že lidé by měli zkontrolujte návratovou hodnotu fclose obecně, protože konečné vyprázdnění může selhat, ale to není nutné pro soubory, které jsou otevřeny pouze pro čtení, nebo pokud fflush byl volán ručně před fclose (což je každopádně chytřejší idiom, protože je snazší zvládnout chybu, když máte soubor stále otevřený).


fclose(NULL) měl by povést se. free(NULL) uspěje, protože to usnadňuje psaní kódu čištění.

Bohužel to tak nebylo definováno. Proto nemůžete použít fclose(NULL) v přenosných programech. (Např. viz http://pubs.opengroup.org/onlinepubs/9699919799/).

Jak již uvedli ostatní, obecně nechcete, aby se vrátila chyba, pokud předáte hodnotu NULL na nesprávné místo. Chcete varovnou zprávu, alespoň při ladění/testování sestavení. Dereferencování NULL vám dává okamžitou varovnou zprávu a příležitost shromáždit zpětné sledování, které identifikuje chybu programování :). Když programujete, segfault je ta nejlepší chyba, kterou můžete dostat. C má mnohem více jemných chyb, jejichž ladění trvá mnohem déle...

Chybové návraty je možné zneužít ke zvýšení odolnosti proti programovým chybám. Pokud se však obáváte, že pád softwaru ztratí data, mějte na paměti, že přesně totéž se může stát např. pokud váš hardware ztratí energii. Proto máme automatické ukládání (od unixových textových editorů s dvoupísmennými názvy jako ex a vi). Stále by bylo vhodnější, aby váš software spadl viditelně, než aby pokračoval v nekonzistentním stavu.


Chyby, o kterých mluví manuálová stránka, jsou chyby běhu, nikoli chyby programování. Nemůžete jen tak předat NULL do jakéhokoli API, které očekává ukazatel a očekává, že toto API udělá něco rozumného. Předání NULL ukazatel na funkci, o které je zdokumentováno, že vyžaduje ukazatel na data, je chyba.

Související otázka:Mám v C nebo C++ zkontrolovat parametry ukazatele proti NULL/nullptr?

Abych citoval R. komentář k jedné z odpovědí na tuto otázku:

... zdá se, že zaměňujete chyby vyplývající z výjimečných podmínek v operačním prostředí (fs plný, nedostatek paměti, výpadek sítě atd.) s chybami v programování. V prvním případě je samozřejmě potřeba, aby je robustní program dokázal elegantně zvládnout. V druhém případě je robustní program nemůže zažít.


Linux
  1. Konfigurační test Apache2 se nezdařil:Chyba segmentace (vyřazení jádra) [Vyřešeno]

  2. Proč *ne* analyzovat `ls` (a co dělat místo toho)?

  3. Chyba Gparted – chyba segmentace (vyřazeno jádro)?

  1. Proč ENOENT znamená Žádný takový soubor nebo adresář?

  2. Chyba segmentace při vytvoření Qt QApplication s new

  3. Chyba při používání novější verze glibc

  1. Proč se přesměrování Stderr na /dev/null provádí tímto způsobem?

  2. Chyba C++:nedefinovaný odkaz na 'clock_gettime' a 'clock_settime'

  3. Proč se mé ethernetové rozhraní nazývá enp0s10 místo eth0?