Folosirea variabilelor volatile în si

Evaluare: 5/5


Ați întâlnit codul în timp ce lucrați cu codul C sau C ++ cu următoarele situații?

- cod care funcționează bine până când activezi optimizarea







- cod care funcționează bine până când întreruperile sunt dezactivate

- Sarcini RTOS care funcționează excelent în mod izolat, până când a fost creată o altă sarcină

Dacă ați răspuns "da" la una dintre aceste afirmații, probabil că nu utilizați cuvântul cheie volatil. Nu sunteți singuri. Utilizarea acestui calificativ este puțin înțeleasă de mulți programatori, deoarece majoritatea cărților despre programarea C nu acordă atenția corespunzătoare acestui subiect.

Cuvântul cheie volatil este scris înainte sau după tipul de date al variabilei declarate.

volatil intfoo;

int volatilefoo;

Indicatorii pentru variabilele volatile sunt declarați după cum urmează.

volatile int * pReg;

int volatile * pReg;

Voturile volatile la variabilele non-volatile sunt extrem de rare (cred că le-am folosit doar o singură dată), dar doar în cazul în care le dau sintaxa:

int * volatile p;

Și, pentru completitudine, dacă aveți nevoie de un pointer volatil la o variabilă volatilă, ar trebui să scrieți:

int volatile * volatile p;

Dacă utilizați volatile pentru un struct sau o uniune, acțiunea specificatorului se va propaga la întregul conținut al structurii / uniunii. Dacă nu doriți acest lucru, puteți aplica specificatorul volatil la elementele individuale ale structurii / uniunii.







Utilizarea corectă a specificatorului VOLATILE

O variabilă trebuie declarată cu cuvântul cheie volatil ori de câte ori valoarea sa se poate schimba în mod neașteptat.

uint8_t * pReg = (uint8_t *) 0x1234;

// Așteptați ca registrul să devină zero

În acest caz, aproape sigur va exista un eșec de îndată ce veți permite optimizarea. Compilatorul va genera un cod de asamblare similar cu acesta:

Argumentare SEO este destul de simplu: deja luate în considerare valoarea acumulatorului (a doua linie de cod), nu este nevoie să-l citească din nou, pentru că valoarea va fi întotdeauna același. Astfel, în a treia linie, ajungem într-o buclă nesfârșită. Pentru a forta compilatorul să facă ceea ce avem nevoie, vom schimba descrierea la:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

Codul de asamblare arată acum astfel:

A fost atins progresul necesar al procesului.

Probleme dificile pot apărea în registrele care au caracteristici specifice. De exemplu, multe periferice conțin registre care sunt curățate pur și simplu prin citirea lor. Câteva lecturi adiționale dincolo de intențiile dvs. (sau invers, mai puțin decât ați planificat) pot duce, în aceste cazuri, la rezultate neașteptate.

În ceea ce privește microcontrolere AVR de programare, nu este nevoie de a utiliza indicii pentru registrele periferice, deoarece codul în acest caz, o foarte greoaie. Pashgan.

Rutina de întrerupere a serviciului (ISR)

Întreruperii de întrerupere determină adesea valoarea variabilelor care sunt verificate în corpul principal al codului. De exemplu, o întrerupere a portului serial poate verifica fiecare caracter primit pentru a vedea dacă acesta este un caracter de sfârșit de linie (probabil indicând sfârșitul mesajului). Dacă caracterul este sfârșitul liniei, dispozitivul de tratare a întreruperii poate seta drapelul global. Aplicarea incorectă în acest caz poate fi următoarea:

int etx_rcvd = FALSE;







Articole similare

Trimiteți-le prietenilor: