Steaguri pe bază de embleme bazate pe enum

Când lucrați cu microcontrolere la un nivel scăzut, este adesea necesar să lucrați cu biți individuali în registrele de configurare, cu diferite steaguri de stare etc. În mod tradițional, în limbajul "C", variabilele întregi și operațiile de biți cu acestea sunt utilizate pentru aceasta. Totul pare simplu și clar, ce altceva este necesar? Siguranța tipului. O variabilă întregă folosită pentru steaguri poate fi atribuită oricărui număr absurd, iar compilatorul nu va deranja deloc.

Să mergem mai departe să practicăm. Numele simbolice pentru steaguri sunt convenabil declarate folosind enum:

O variabilă obișnuită de pavilion:

În timp ce totul pare curat și frumos, dar nimic nu ne împiedică să scriem așa:

Ce steaguri au fost aruncate, instalate? Compilatorul încă mânca și nu sufoca, myFlags - variabila număr întreg și poate stoca aproape orice. Dar, uneori, pare atât de simplu în loc de linie lungă, ca de exemplu: flag0 | flag1 |. | | flagM scrie un număr scurt care pare atât de evident ... Acum - este evident, mâine pentru tine, nu înseamnă nimic, ci pentru alții, chiar mai mult.
Vreau să mă protejez de astfel de "oportunități suplimentare" care funcționează cu steaguri ar fi mai riguroase. Evident, în acest caz, trebuie să păstrați steaguri, nu într-o variabilă întreg, ci într-o variabilă a tipului enum - MyFlags.

Prima linie funcționează conform așteptărilor, steagurile variabile nu pot fi atribuite oricum - adică numai elementele de enumerare. Dar aici suntem asteptati de o problema, expresia flag0 | flag1 (ca și alte operații de biți cu enumerări) este de tip int, iar a doua linie va provoca o eroare de compilare. Va trebui să utilizați distribuții, dar făcând acest lucru în mod explicit cu fiecare operațiune de pavilioane nu este mai bună decât depozitarea steagurilor în int:

Puteți ascunde aceste conversii de tip în funcții speciale (nu numai în macro-uri, altfel tot controlul de tip va merge în pădure):

Scrieți astfel de funcții pentru un număr rezonabil de argumente și utilizați:

Se pare că nu este rău - ne-am atins deja scopul nostru, tipul de securitate. În C + +, puteți face chiar mai bine - doar supraîncărcați operațiunile bit flag pentru enum pavilionul nostru:

Aducerea argumentelor la int în acest caz este necesară pentru ca nu există o recurență infinită :) Acum este mult mai ușor să folosiți steaguri:

Pentru a facilita utilizarea ulterioară, împingeți operatorii supraîncărcați pentru enum-uri în macro-uri:

Acum, pentru a utiliza steagurile de tip sigur, trebuie doar să scrieți enumerarea corespunzătoare și să setați operațiile de biți pentru aceasta:

Astfel de steaguri, de exemplu, sunt convenabile pentru inițializarea diferitelor periferice. Un exemplu de inițializare a unui modul USART în STM32:

Cum rămâne cu situația când creați fundația, arhitectura proiectului și completați punerea sa în aplicare și însoțiți ceilalți oameni? Cu cât au mai puține șanse să înșele, cu atât mai multe șanse ca proiectul să rămână holist și să se autofinanțeze. Probabil că aveți o mică experiență de lucru în echipă :)

da aici majoritatea nu este deosebit de mare

Ololo, nu m-am înșelat în munca în echipă?) M-am gândit la arhitectura, care este pusă în aplicare de alții, adesea de indieni.

Conversiile de tip explicite în acest caz vor fi imediat evidente și, spre deosebire de constanta întregului, le este ușor să le găsim folosind expresii regulate.
Dacă poți avea grijă de tine și de alții din astfel de lucruri și gratuit, de ce nu o faci?

Simplitatea, printre altele, promovează lizibilitatea și sustenabilitatea. Dacă, desigur, sub simplitate, nu luați 0x2F în loc de pavilion1 flag2 | flagN.
Dar în înțelegerea mea este frumos - este simplu, elegant din punct de vedere tehnic și ușor de citit.

Nu mai puțin program eficient vă permite să scrie și vechi-bun C. Și dacă nu puteți vedea diferența ... Programele nu mai puțin eficiente vă permit să scrieți coduri binare vechi vechi. Ei bine, despre bine, eu conduc. Dar, de asemenea, C ++ în mâinile cu pricepere a aceluiași C diferă.

Privind la această "simplitate", vrei să plângi. (
Blah, chiar și un pic în registru nu poate fi instalat, fără a ucide un kilometru de scoici în jurul celui mai elementar operator |
De asemenea, pentru a face restricții fără sens - aceasta nu este o cale C. De asemenea, să nu folosești 0x2F în loc de pavilion1 flag2 | flagN nevoie de creier în mod semnificativ mai puțin decât să mănânce în toate aceste cod junk pe nenorocit C + +.
În general, nu te vreau. /

Ei bine, la nivelul programului său, este posibil să bust (dacă lucrați singur - altfel astfel de trucuri pot fi urmărite cu scopul de a face normal să scrie restul). Dar la nivelul bibliotecii este deja destul de semnificativă.
Un exemplu, apropo, judecând după forma sa, este doar din biblioteca UART.

De câteva ori fruntea șmyaknut despre Claudia și va scrie în mod normal. )
Și încă o dată, fără a avea nevoie de supraîncărcare, operatorii standard nu au nevoie. Nu este nevoie să faceți lucrurile mai complicate și mai complicate pentru că puteți.

Dacă totul era atât de simplu, Wirth nu ar fi dezvoltat toate limbile noi care nu-i permit să se împuște în picioare :)

Dacă am înțeles corect textul în limba engleză, atunci în ea, potrivit uniunii, nu se spune nimic nou.
Și astfel este clar că atunci când scrieți un flotor în uniune, nu puteți citi ca int în speranța de a obține întreaga parte a numărului. Chiar dacă uniunea constă din float și int.

ps. dacă utilizați o structură anonimă, atunci înregistrarea steagurilor va fi mai simplă


Nu știu nimic despre mister, cu excepția faptului că este.

Nu, nu este. Prin scrierea float la uniune, nu vă puteți aștepta ca din int veți citi reinterpret_cast (float). Și dacă scrieți flag.f = 0, atunci nu există nicio garanție că acest lucru va reseta drapelele de biți. Da, de obicei funcționează, dar conform standardului este UB.

Prin scrierea float la uniune, nu vă puteți aștepta ca din int veți citi reinterpret_cast (float).
Nu este clar de ce s-ar putea să ai nevoie de o astfel de distribuție. Există, de asemenea, acces separat la int și separat la float.
Sau despre faptul că este imposibil să definiți ceea ce este stocat în interiorul uniunii în fiecare moment al timpului - int sau float? Este o da.
lag.f = 0 - nu există nicio garanție că acest lucru va reseta drapelele de biți. Da, de obicei funcționează, dar conform standardului este UB. Cu câmpuri bit, UB nu oferă nici mai puține probleme.