Az illékony kulcsszó használata c, avr, programozásban
Ismered a következő eseteket a C vagy C ++ beágyazott rendszer kódjában?
• A kód jól működik, amíg a fordító optimalizálása megszűnik.
• A kód jól működik - a megszakítások engedélyezéséig.
• vadon dolgozó hardver-illesztőprogramok.
• Az RTOS feladatok elszigetelten működnek - addig, amíg valami más feladatot generál.
Ha a válasz "igen" a fenti kérdések bármelyikére, akkor valószínűleg nem használja az illékony kulcsszót. De te vagy az egyetlen. Kevés programozó érti, hogyan kell illékonyan használni. Sajnos sok könyv a C programozási nyelvre kevés figyelmet fordít az illékony selejtezőre.
A C illékony kulcsszava egy olyan minősítő, amely hozzáadódik a változó deklarációhoz (változó típusú selejtező, hasonló a const kvalifikátorhoz). Azt mondja a fordítónak, hogy a változó értéke bármikor megváltoztatható - anélkül, hogy a kódolvasó kódot a fordító láthatóvá válna. Ennek következményei nagyon komolyak. Azonban, mielőtt ezzel foglalkoznánk, nézzük meg a szintaxist.
[Az illékony kulcsszó szintaxisa]
Egy változónak változékonynak való megjelenítéséhez adja meg az illékony kulcsszót az adattípus előtt vagy után a változó definícióban. Például az alábbiak egyenértékűen definiálják a foo változót, mint egészet az illékony tulajdonsággal:
Ugyanez vonatkozik az illékony változókra mutató mutatókra is, különösen a memóriával leképezett I / O regiszterekhez. Mindkét deklaráció ugyanúgy definiálja a pReg-t mint mutatót egy alá nem írt 8-bites egész számra (byte) az illékony tulajdonsággal:
Az illékony mutatók nem illékony adatokra nagyon ritkák, de érdemes megemlíteni a következő szintaxist:
És csak a teljesség kedvéért, ha hirtelen valóban szükséged van arra, hogy illékony mutatót kapj egy változó változóhoz, írd ilyet így:
Végül, ha illékony struktúrára vagy szakszervezetre alkalmaztál, a struktúra / csatlakozás összes tartalma (minden mezője) megkapja az illékony tulajdonságokat. Ha nincs szüksége erre a viselkedésre, csatolja az illékony minősítőt a struktúra / unió egyes mezőihez (tagjaihoz).
[Az illékony kulcsszó helyes használata]
A változót váratlanul módosítani kell, ha változik. A gyakorlatban az ilyen változók közül csak háromféle lehet:
1. A processzor vagy annak perifériaeszköz memóriarekordjai (memóriával leképezett perifériás regiszterek).
2. Globális változók, amelyeket a megszakítási szolgáltatás rutin (ISR) kódjában módosítottak.
3. Globális változók, amelyek különböző feladatokkal foglalkoznak egy többszálas alkalmazásban (általában más RTOS-folyamokra utalnak).
Tekintsük a három eset mindegyikét részletesebben.
Általában az ilyen kód hibát okoz, amint engedélyezi a fordítóoptimalizációt, amikor a mellékelt optimalizálással ilyen kódot generál:
Most az assembler kód lesz így:
Megvalósul a program szükséges viselkedése.
Az elhanyagolt problémák általában különleges tulajdonságokkal rendelkező nyilvántartásokban merülnek fel. Például egyes perifériás eszközök olyan regisztereket tartalmaznak, amelyek nullázásával egyszerűen elolvashatók. További számuk (vagy kevesebb olvasataik) a vártnál, teljesen kiszámíthatatlan eredményekhez vezethetnek.
Megszakítja a kezelőket. A megszakítási szolgáltatási rutinok gyakran olyan változókat állítanak be, amelyek a fő kódban (a megszakításon kívül dolgoznak) vagy egy másik megszakítás kódjában vannak. Például a soros port ISR-e ellenőrizheti az egyes szimbólumokat az ETX szimbólum megjelenítéséhez (feltételezhetően az üzenet vége). Ha egy ETX szimbólumot talál, az ISR globális zászlót állíthat be. A helytelen végrehajtás lehet a következő:
Ha a fordítóoptimalizálás le van tiltva (általában hibakeresés esetén), ez a kód működhet. Azonban szinte minden többé-kevésbé méltó optimalizáló "megtöri" ezt a kódot. A probléma az, hogy a fordítónak nincs olyan információja, hogy az etx_rcvd változó megváltoztatható az ISR-ben. Mindaddig, amíg a fordító úgy gondolja, ezért a kifejezés! Ext_rcvd mindig igaz, tehát a hurok soha nem fog befejezni. Ezért az optimalizáló egyszerűen törli az összes kódot az optimalizáló által a loop-test után. Ha szerencsés vagy, a fordító ezt jelentené. Ha nem vagy szerencsés (vagy még nem tanulta meg, hogyan kell figyelni a fordítói üzenetekre), a kód megszakad. Természetesen a hibát azonnal át kell adni a "pocsék optimizálónak".
Ebben a helyzetben az a megoldás, hogy az etx_rcvd változót az illékonynak nyilvánítsuk. Ezután minden problémája (vagy legalábbis az ezzel kapcsolatos probléma) eltűnik.
Többszálú alkalmazások. Annak ellenére, hogy a jelen sorok (sorok), csatorna (csövek), és más cseremechanizmusok egy többszálú környezetben (RTOS), továbbra is elterjedt gyakorlat közötti információcserét a két folyam keresztül megosztott memória (globális változó). Még, ha hozzá az elmozdulás tervező a kódot a fordító még mindig semmi nem utal arra, hogy a munka kontextusában vált, és hogy ez megtörténhet. Ebben az esetben, amikor egy másik feladatot módosította a közös globális változó, az ugyanaz, mint a megszakítás kezelő is előfordulhat, a fentiek szerint. Az előző példához hasonlóan a megosztott változót be kell illeszteni. Például itt lehetnek problémák a kódban, amikor a közös változó cntr-t a különböző feladatokból érik el:
Ez a kód valószínűleg nem fog működni, ha az optimalizálás engedélyezett. A cntr változékonynak nyilvánítása a helyes megoldás a probléma megoldásához.
A memóriával leképezett regiszterekhez való hozzáférés (memóriával leképezett regiszter vagy MMR) a mutatók segítségével történik. Itt van egy másik példa, ahol problémák merültek fel a PIC mikrokontroller C-kódszójának hiányában. A kódnak két periférikus regiszter közötti permutációját kell elvégeznie:
Néhány fordítóprogram lehetővé teszi, hogy implicit módon minden változót feltüntessünk. Ne adjon bele ennek a kísértésnek, mert lényegében elgondolkodik a gondolkodásban (valamint az optimalizálás letiltásával). Ez egy kevésbé optimalizált kóddal is járhat.
Továbbá utasítsa el a kísértést, hogy mindig kapcsolja ki az optimalizálót. A modern optimalizátorok olyan jóak, hogy lehetetlen emlékezni arra, hogy az optimalizálás hibákat okoz. Inkább az optimalizálás bevitele lehetővé teszi, hogy azonosítsa azon kód esetleges hibáit, amelyeket egyébként nem észlelne.
Ha valamilyen hibajavítást adtál meg a javításhoz, butaan hajtsd végre a grek műveletet a forráskód szövegein az illékony kulcsszó keresésében. Ha a grep kimenete üres, az itt megadott példák jó kiindulási pontot jelentenek a hibaelhárításhoz.
[Mi a helyzet a struktúrákkal? ]
Hogyan használhatok illékony struktúrákat és mutatókat a struktúrákhoz? Meg kell-e határoznunk egy mutatót egy olyan szerkezetre, amely illékony, vagy minden egyes szerkezeti elemnek illékonynak vagy nem illékonynak kell lennie? Talán valamilyen perifériás nyilvántartások nem kell használni illékony, mert értékük nem változik, de az állapota a megszakítás maszk, a vételi puffer, és így tovább. D. változhatnak, és ezért meg kell határozni például illékony?
Hol kell elhelyezni az illékony kulcsszót ezekre a definíciókra annak érdekében, hogy a mutatóval helyesen használjam a struktúrát?
Ebben a példában a legjobb gyakorlat a következő struktúra meghatározása az I / O MMR regiszterekkel: