Otázka:
Co se stane, když dojde k chybě za běhu?
The Guy with The Hat
2014-02-14 07:33:03 UTC
view on stackexchange narkive permalink

Co se stane, když se v programu vyskytne runtime chyba? Zastaví se provádění programu? Existuje nějaký způsob, jak přimět Arduino, aby mi řeklo, v čem je chyba?

šest odpovědi:
Ricardo
2014-02-15 03:24:20 UTC
view on stackexchange narkive permalink

Nejprve se podívejme na několik příkladů toho, co se může pokazit.

Neinicializované místní proměnné

  void setup () {int status; pinMode (13, VÝSTUP); digitalWrite (13, status);} 

Jak zdůrazňuje Edgar Bonet v komentářích, místní proměnné jako status v kódu výše nejsou implicitně inicializovány kompilátorem C ++. Výsledek výše uvedeného kódu je tedy neurčitý. Abyste tomu předešli, ujistěte se, že vždy přiřadíte hodnoty místním proměnným.

S globálními a statickými proměnnými se věci trochu liší:

Globální a statické proměnné zaručeně být inicializován na 0 standardem C.

Zdroj: Referenční příručka AVR Libc - často kladené otázky - Neměl bych inicializovat všechny své proměnné?

To znamená, že byste se neměli starat o jejich inicializaci na 0 v kódu. Ve skutečnosti byste se tomu měli opravdu vyhnout, protože inicializace může plýtvat pamětí. Inicializujte je pouze na jiné hodnoty než 0.

Přetečení paměti

  int pole [10]; int v = pole [100]; pole [-100] = 10; 

Prvním problémem zde je, že nevíte, co bude přiřazeno v, ale horší je, že nevíte, co jste pokazili s přiřazením na pozici -100 z array.

Přejít na neplatnou instrukci

  void doSomething (void) {for (int i = 0; i < 1000; i ++) ; } void setup () {void (* funcPtr) (void); funcPtr = &doSomething; funcPtr (); // volá doSomething (); funcPtr = NULL; funcPtr (); // undefined behavior}  

První volání funkce funcPtr () bude ve skutečnosti volání funkce doSomething () . Hovory jako druhé mohou vést k nedefinovanému chování.

Další špatné věci, které se mohou stát

Může vám například dojít paměť RAM. Co jiného. V každém případě si myslím, že váš program poběží dál, pravděpodobně ne tak, jak jste zamýšleli.

Druhy ochrany

V počítačových systémech se problémy, jako jsou tyto, obvykle řeší na různých úrovních:

  1. kompilátor
  2. běh programovacího jazyka (například v Javě) .
  3. Operační systém nebo procesor (pokud vaše paměť přistupuje k pozici mimo hranice adresního prostoru vyhrazeného pro váš program, OS nebo procesor mohou mít bezpečnostní mechanismy, které tomu zabrání)

Arduina mají pouze omezenou ochranu kompilátoru a pravděpodobně nic jiného. Dobrou zprávou je, že nemají více úkolů, takže jediný ovlivněný program je váš. V každém případě některá z těchto chyb povede k nevyzpytatelnému chování.

Odpovědi

Předpoklady jsou všechny problémy, které jsem uvedl výše, jsou problémy za běhu.

Co se stane, když se v programu vyskytne runtime chyba?

Program bude pokračovat a to, co se stane, bude záviset na vedlejších účincích runtime chyby. Volání ukazatele funkce null pravděpodobně způsobí, že program skočí na neznámé místo.

Zastaví se provádění programu?

Ne, to bude pokračovat, jako by se nic mimořádného nestalo, pravděpodobně bude dělat to, co jste nechtěli. Může se resetovat nebo jednat nepravidelně. Může změnit některé vstupy na výstupy a vypálit jeden nebo dva senzory (ale to je vysoce nepravděpodobné ).

Existuje nějaký způsob, jak přimět Arduino, aby mi řeklo, co chyba je?

Nemyslím si to. Jak jsem již řekl, ochranné mechanismy tam nejsou. Neexistuje žádná runtime podpora z jazyka, žádný OS, žádné kontroly hardwaru pro přístup do paměti mimo hranice (bootloader se nepočítá jako jeden). Musíte jen dávat pozor na svůj program a pravděpodobně si nastavit vlastní bezpečnostní sítě.

Důvodem nedostatečné ochrany je pravděpodobně to, že řadiče Arduino jsou příliš levné, mají příliš málo paměti a neměly by spouštět nic příliš důležitého (ano, zdá se, že AVR někde existuje zřeknutí se odpovědnosti, abyste MCU nepoužívali běžně používá Arduino v systémech podpory života).

Skvělý! Nejlepší odpověď, kterou jsem zatím viděl na Arduino.SE!
Dík!! Myslím, že bychom se měli snažit dávat co nejvíce skvělých odpovědí. Trochu mě však znepokojuje skutečnost, že nemáme tolik odborníků na SKUTEČNÉ EE, kteří by se mohli podívat na odpovědi jako já a najít nějaké do očí bijící chyby. Ve skutečnosti je to důvod, proč jsem zveřejnil odpověď, i když toho o AVR MCU tolik nevím. To je vidět, jestli někoho přimíme, aby to napravil. Určitě nechceme, aby chytré penny jako já říkaly věci, které nejsou správné, a aby jim to uniklo. Ale to je pravděpodobně diskuse o webu Meta.
Poškodilo by něco z toho Arduino?
@AnnonomusPerson - Jediným pravděpodobným mechanismem poškození by byl kód, který mění stav pinů způsobem, který má za následek tvrzení o sběrnici (např. ATmega se snaží nastavit pin vysoko, zatímco externí hardware jej nastavuje na minimum). Je také možné, že pokud existuje externí hardware, který ovládá ATmega, který nedokáže zvládnout určité stavy kontrolního vstupu, * externí hardware * by mohl způsobit nějaký způsob selhání a poškození, ale arduino s ničím to nepřipojilo docela neprůstřelně. Arduinos mají sériové odpory, aby se zabránilo možným problémům s konflikty na sériových linkách.
@Ricardo - Jeden komentář, který bych udělal, je, že neexplicitně inicializované proměnné nejsou * nutně * neinicializované. Proměnné definované mimo funkce mají obecně to, co se nazývá „doba trvání automatického úložiště“, které se poté výchozí inicializuje na nulu. Další informace najdete na stránce http://en.cppreference.com/w/cpp/language/default_initialization. Inicializační chování je natolik složité, že je pravděpodobně nebezpečné spoléhat se na něj, ale vytváření obecných příkazů * pravděpodobně * není skvělý nápad.
Kromě toho je SRAM inicializován na 0 při resetu nebo spuštění, takže můžete provést * některé * informované odhady o neinicializovaných proměnných, pokud chcete žít nebezpečně. Na toto chování byste se neměli * spoléhat *, ale je to zajímavé.
Zde je zajímavý příklad toho, co se stane, když vám dojde SRAM: http://electronics.stackexchange.com/questions/42049/arduino-serial-print-changes-behavior-of-program-undesireably/42069. V zásadě jde o hromádku, která hromadí část hromady, nebo naopak. To může dělat zajímavé věci, jako je poškození některé části stack-frame (vrácení zlomené funkce atd.) Nebo zápis neplatných dat do proměnných.
Relevantní je také otázka týkající se rekurze: http://arduino.stackexchange.com/questions/355/how-much-can-i-recurse-how-much-can-i-recurse-how-much-caqfsdrfw, protože rekurze je jeden ze snadných způsobů vyhodit hromádku.
@FakeName - správně! Upravím svou odpověď, abych opravil tvrzení o neinicializovaných proměnných. Pokud jde o další skvělé návrhy, které jste zveřejnili, proč jim nedáte odpověď a já na ni přidám odkaz? Rád vás vidím (nebo možná jen obrázek vaší naštvané kočky) tady.
@FakeName - BTW, ten obrázek mi vždy připomíná skvělou techniku ​​Cat Yodeling * z * [Engineer's Guide to Cats] (http://www.youtube.com/watch?v=mHXBL6bzAR4) v 4:57 min.
Jedna poznámka: `` Dobrou zprávou je, že jste se pokazili pouze s RAM a ne s EEPROM, takže váš program je v bezpečí. '' Program spuštěný na ATmega je uložen v paměti Flash, ne v EEPROM. EEPROM má obvykle pouze 1–2 kB a slouží spíše k ukládání malého množství energeticky nezávislých dat (myslím: nastavení konfigurace uživatele, sériové číslo atd.), Nikoli skutečného kódu.
@ConnorWolf správně! Dobře spatřen. Jen jsem upravil a opravil svou odpověď.
`překladač C ++ to dělá za vás. Nastaví ji jako nulu. Místní proměnné nejsou inicializovány. Ve vašem příkladu interpretuji `status` jako místní, proto je to špatné. `není považováno za dobrou praxi spoléhat se na toto chování` ve skutečnosti je ** považováno za dobrou praxi spoléhat se na toto chování pro globální proměnné, protože je zaručeno, že budou inicializovány nulou a nula inicializující globály ve vašem kódu může plýtvat pamětí (ačkoli současné kompilátory by měly být dostatečně chytré, aby se tomu vyhnuly) viz http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_varinit.html
Napsali jste: „_`array [-100] = 10;„ [...] zpackali jste pouze RAM [...], takže váš program je v bezpečí ._ “Můžete nakonec skončit zápisem do IO prostoru MCU, který je mapován v paměti přímo pod RAM na AVR. To rozhodně není bezpečné. „_ [Volání ukazatele funkce NULL], který je ekvivalentní soft boot_“. Nepřesně. Program se restartuje od samého začátku: inicializuje ukazatel zásobníku, RAM, volání main atd. Ale na rozdíl od měkkého bootování to _not_ resetuje IO registry do výchozího výchozího stavu.
@Connor Wolf: Napsali jste: „_RAM je inicializován na 0 při resetu nebo spuštění_“. To není správné. Na rozdíl od IO registrů není SRAM inicializován hardwarem při spuštění. Sekce BSS paměti RAM (a _ pouze_ v této části) je inicializována na nulu pomocí modulu runtime C. Sekce DATA je inicializována na jakýkoli obsah, který programátor požadoval. Veškerá zbývající RAM zůstane neinicializovaná.
@EdgarBonet - bod převzat. Škoda, že nemůžu upravovat své starší komentáře.
@EdgarBonet - děkuji za poukázání na problém s mojí odpovědí. Přečetl jsem odkaz, který jste poskytli, a pokusili jsme se opravit výroky o lokálních proměnných. Mohli byste to prosím zkontrolovat? Dík!
Vaše prohlášení o restartu programu při volání ukazatele funkce NULL bylo správné, alespoň na AVR. Jen jsem poukazoval na to, že restartování programu není úplně stejné jako reset. BTW, do procesu není zapojena žádná nelegální instrukce. "_ Mohl byste to prosím zkontrolovat? _" Nemohu ve vaší odpovědi najít nic špatného.
Connor Wolf
2014-02-15 05:26:18 UTC
view on stackexchange narkive permalink

Nejsou žádné výjimky za běhu. Existuje pouze nedefinované chování.

Opravdu neexistují žádné výjimky vůbec . Pokud se pokusíte provést neplatnou operaci, budou její výsledky neznámé.

Neexistuje vůbec žádná kontrola běhu, kromě toho, co implementujete . Váš program běží na hardwaru z holého kovu. Je to ekvivalent Desktop, který běží v ring-0 po celou dobu, protože ATmega nemá prsteny .

nio
2014-02-15 17:44:12 UTC
view on stackexchange narkive permalink

Existuje jeden mechanismus, který může dostat MCU z nevyzpytatelného stavu, a to je časovač hlídacího psa . Pokud implementujete nějaký kód, který se bude opakovaně spouštět ve smyčce, který se nespustí kdykoli déle než nějaký pevný čas, můžete tento čas nastavit jako sledovací období a povolit časovač.

Potom musíte opakovaně vynulovat časovač ve smyčce. Pokud váš kód zamrzne v nějaké smyčce podmínek, která nikdy neskončí, pak se hlídací pes započítá na nulu a nakonec vynuluje MCU.

Tímto způsobem ztrácíte data, ale pokud spustíte AVR WDT v režimu přerušení , můžete uložit některá data před resetováním MCU.

Takže časovač hlídacího psa může chránit váš kód před občasnými nechtěnými nekonečnými smyčkami.

Dokumentace: AVR132: Použití vylepšeného hlídacího psa Časovač

sachleen
2014-02-14 07:47:14 UTC
view on stackexchange narkive permalink

Pro něco takového byste potřebovali hardwarový debugger. Obvykle však uvidíte, že se program nechová tak, jak očekáváte, a bude se muset podívat na tuto část kódu, aby identifikoval problém.

Běžný / rychlý / snadný způsob, jak to udělat, je přidejte tiskové příkazy k vytištění hodnot proměnných nebo cokoli jiného, ​​abyste věděli, že se program bez problémů dostane do tohoto bodu v kódu. To vám pomůže problém dále izolovat.

Věřím, že VisualMicro obsahuje některé funkce ladění.

TheDoctor
2014-02-14 07:50:32 UTC
view on stackexchange narkive permalink

Předpokládám, že procesor AVR nemá žádné nástroje pro detekci nebo obnovení chyb. Může se prostě zastavit nebo pokračovat v ignorování chyby a důsledků. Jak řekl sachleen, měli byste do svého programu přidat nějaké ladicí příkazy, které tisknou data uprostřed operace, abyste otestovali, zda funguje. Pokud používáte emulátor a nastavíte zarážky, můžete snadno najít problém.

user28739
2016-12-03 04:18:45 UTC
view on stackexchange narkive permalink

Arduino se restartuje (tj. znovu spustí setup () a loop () ).

Ne nutně. Chyba běhu může způsobit, že program přejde do smyčky bez restartu.


Tyto otázky a odpovědi byly automaticky přeloženy z anglického jazyka.Původní obsah je k dispozici na webu stackexchange, za který děkujeme za licenci cc by-sa 3.0, pod kterou je distribuován.
Loading...