Nepochopitelné chování

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, ...)
Odpovědět
Uživatelský avatar
kiRRow
Příspěvky: 1170
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Nepochopitelné chování

Příspěvek od kiRRow » 15 zář 2023, 16:39

Zdravím, včera jsem zažil docela nepochopitelnou věc. Koncept programu je takový, že z loopu je neustále volána funkce, která se ale nevykonává celá, vykonávají se pouze některé její části v závislosti na nastavení globálních proměnných. Jelikož spolupracuji s člověkem neprogramátorem, je složité nepoužívat blokující příkazy jako např while. Na zastavení programu používám tlačítko na externí interupt, které nastaví flag isStoped = true, čímž dojde k přerušení cyklu a vyskočení z funkce a k jejímu opětovnému zavolání nedojde do té doby než isStoped = false. No a teď to nepochopitelné ...

Kód: Vybrat vše

// tohle nefunguje, interupt se provede program zustane ve while
void funkce () {
	while(1){if(isStoped) break;
	//kod
	}if(isStoped) return;
}

// tohle funguje naprosto perfektně
void funkce () {
	Serial.println("a");
	while(1){if(isStoped) break;
	//kod
	}if(isStoped) return;
}

// tohle taky funguje naprosto perfektně
void funkce () {
	motorRotator.moveTo(motorRotator.currentPosition());
	while(1){if(isStoped) break;
	//kod
	}if(isStoped) return;
}

// a když si chci vypsat isStoped, tak taky funguje naprosto perfektně
void funkce () {
	while(1){
	Serial.println(isStoped);
	if(isStoped) break;
	//kod
	}if(isStoped) return;
}

// ale když to dám vypsat takhle, tak to nefunguje ... interupt se provede, ale program zůstane v tom while
void funkce () {
	while(1){
	if(isStoped){
		Serial.println(isStoped);
		break;
	}
	//kod
	}if(isStoped) return;
}
může mi někdo nějak rozumně vysvětlit co se děje ? :-D

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

Re: Nepochopitelné chování

Příspěvek od gilhad » 15 zář 2023, 18:15

Zdálky do toho nevidím, ale když slyším "interrupt nastaví" a "program neprovede", tak první otázka je "a je to volatile?" Protože když ne, tak to kompilátor má právo (nikoli však povinnost) považovat za neměnící se a vyoptimalizovat to pryč.

isStoped vypadá na učebnicový příklad ...

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

Re: Nepochopitelné chování

Příspěvek od gilhad » 15 zář 2023, 18:35

Jinak mi přijde zbytečné dávat jako poslední příkaz funkce "if (cosi) return;" protože to stejně po něm hned skončí, ale samozřejmě může to být zkratka za další nezajímavosti ...

Já osobně dávám z hlediska čitelnosti přednost mít středník za "while(){};" a další příkaz, jako to "if" na dalším řádku, takhle se pokaždé zarazím, jestli to není nějaká variace na "do {} while();", kde je ta podmínka na konci, nebo něco jako pythonovské "a=1 if (b>0) else -1" nebo jiná podobná zrůdnost. Jasně, že není, ale nerad nad tím váhám :)

A jinak bych tak od oka řekl, že se překladač někde zmocnil okamžité hodnoty isStoped a dokud ji má ve spárech a viditelně se mu nemění, tak používá pořád tu samou. Ale když musí volat nějaké funkce, které s radostí použijou všechny dostupné registry, tak o ní přijde, pak ji načte znovu a ejhle, ona je pak aktualizovaná ...

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

Re: Nepochopitelné chování

Příspěvek od kiRRow » 15 zář 2023, 18:38

mrknu na to ... zajímavé je, že v jiné části programu ten samý kód problém nedělá (je tam dočasně na prasáka ctrl+c,ctrl+v).

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

Re: Nepochopitelné chování

Příspěvek od gilhad » 15 zář 2023, 18:50

volatile znamená může se měnit "samo", když to chceš použít, musíš to načíst těsně před tím, když to chceš zmenit, musíš to pak okamžitě zapsat.

V Expanduinu se takhle ta deska chová vůči 6809, která k ní přistupuje jako k paměti, ale ta deska ty hodnoty zpracovává a naopak vrací výsledky.
Ve všech programech na té 6809 by teda tenhle kousek paměti měl být deklarován jako volatile.

Tady něco podobného dělá ten interrupt. A když jsme u toho, teoreticky by ten interrupt to mohl nastavovat a shazovat, takže konstrukce

Kód: Vybrat vše

while(true){
    if (isStoped) {
        Serial.print("Zasah ");
        break;
    };
    // kod
};
if (isStoped) Serial.print(" potopeno");
může vypsat nic, jedno, druhé, nebo obě slova. Ale po "Zasah " nemusí " potopeno" následovat, pokud je isStoped volatile.

------

Ono ten překladač (pokud to není volatile) má dost volnou ruku, kdy to bude načítat znovu, nebo zda.

Klidně si v jedné části kódu takhle podrží proměnnou v registrech, protože má registry zrovna volné a v jiné, stejné, mu přijde lepší si v těch registrech držet něco jiného a tu proměnnou prostě použít, zapomenout a znova načíst, než zapomenout něco složitého.

Neuškodí připomenout Nasal demons http://www.catb.org/jargon/html/N/nasal-demons.html

Odpovědět

Kdo je online

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