Am lucrat la mai multe sisteme încorporate diferite. Ei au folosit typedef
s (sau #defines
) pentru tipuri precum UINT32
.
Aceasta este o tehnică bună pe măsură ce acționează acasă dimensiunea tipului la programator și vă face mai conștienți de șansele de supraîncălzire etc.
Dar pe unele sisteme știi că compilatorul și procesorul nu se vor schimba pe durata proiectului.
Deci, ce ar trebui să influențeze decizia dvs. de a crea și de a impune anumite tipuri de proiecte?
EDITAȚI | × Cred că am reușit să pierd ideea întrebării mele și poate că sunt cu adevărat două.
Cu programare încorporată, este posibil să aveți nevoie de tipuri de dimensiuni specifice pentru interfețe și de a face față și resurselor restricționate, cum ar fi RAM. Acest lucru nu poate fi evitat, dar puteți alege să utilizați tipurile de bază din compilator.
Pentru orice altceva, tipurile au o importanță mai mică
Trebuie să aveți grijă să nu provoacă prea mult și este posibil să aveți grijă să folosiți înregistrarea și utilizarea stivei. Care vă poate conduce la UINT16
, UCHAR
.
Folosind tipuri precum UCHAR
se poate adăuga, totuși, "fluff" de compilator. Deoarece registrele sunt de obicei mai mari, unii compilatori pot adăuga un cod pentru a forța rezultatul în tip
i++;can become
ADD REG,1 AND REG, 0xFFwhich is unecessary.
Deci, cred că întrebarea mea ar fi trebuit să fie:
având în vedere constrângerile software-ului încorporat, care este cea mai bună politică de setare pentru un proiect care va avea mulți oameni care lucrează la acesta - nu toți vor avea același nivel de experiență.
Coerență, confort și lizibilitate. "UINT32" este mult mai ușor de citit și mai ușor de scris decât "unsigned long long", echivalent pentru unele sisteme.
De asemenea, compilatorul și procesorul pot fi fixate pe durata unui proiect, dar codul din acel proiect poate găsi o nouă viață într-un alt proiect. În acest caz, având tipuri de date consecvente este foarte convenabil.
The C99 standard has a number of standard sized-integer types. If you can use a compiler that supports C99 (gcc does), you'll find these in
and you can just use them in your projects.
De asemenea, poate fi deosebit de important ca proiectele încorporate să folosească tipuri ca un fel de "plasă de siguranță" pentru lucruri precum conversii de unități. Dacă puteți folosi C ++, înțeleg că există câteva biblioteci "unitate" care vă permit să lucrați în unități fizice definite de sistemul tip C ++ (prin șabloane) care sunt compilate ca operații pe tipurile scalare de bază. De exemplu, aceste biblioteci nu vă vor lăsa să adăugați un distance_t
la un mass_t
deoarece unitățile nu se aliniază; veți avea de fapt o eroare de compilator.
Chiar dacă nu puteți lucra în C sau într-o altă limbă care vă permite să scrieți codul în acest fel, puteți folosi cel puțin sistemul de tip C pentru a vă ajuta să prindeți erori de genul asta cu ochii. (Aceasta a fost de fapt intenția inițială a notației ungare a lui Simonyi.) Doar pentru că compilatorul nu va striga la tine pentru adăugarea unui meter_t
la un gram_t
nu înseamnă că nu trebuie Nu folosiți astfel de tipuri. Revizuirile de cod vor fi mult mai productive la descoperirea erorilor de unitate atunci.
Folosesc abstractizarea de tip foarte rar. Iată argumentele mele, sortate în ordinea crescătoare a subiectivității:
Local variables are different from struct members and arrays in the sense that you want them to fit in a register. On a 32b/64b target, a local int16_t
can make code slower compared to a local int since the compiler will have to add operations to /force/ overflow according to the semantics of int16_t
. While C99 defines an intfast_t
typedef, AFAIK a plain int will fit in a register just as well, and it sure is a shorter name.
Organizations which like these typedefs almost invariably end up with several of them (INT32, int32_t, INT32_T
, ad infinitum). Organizations using built-in types are thus better off, in a way, having just one set of names. I wish people used the typedefs from stdint.h or windows.h or anything existing; and when a target doesn't have that .h file, how hard is it to add one?
The typedefs can theoretically aid portability, but I, for one, never gained a thing from them. Is there a useful system you can port from a 32b target to a 16b one? Is there a 16b system that isn't trivial to port to a 32b target? Moreover, if most vars are ints, you'll actually gain something from the 32 bits on the new target, but if they are int16_t
, you won't. And the places which are hard to port tend to require manual inspection anyway; before you try a port, you don't know where they are. Now, if someone thinks it's so easy to port things if you have typedefs all over the place - when time comes to port, which happens to few systems, write a script converting all names in the code base. This should work according to the "no manual inspection required" logic, and it postpones the effort to the point in time where it actually gives benefit.
Now if portability may be a theoretical benefit of the typedefs, readability sure goes down the drain. Just look at stdint.h: {int,uint}{max,fast,least}{8,16,32,64}_t
. Lots of types. A program has lots of variables; is it really that easy to understand which need to be int_fast16_t
and which need to be uint_least32_t
? How many times are we silently converting between them, making them entirely pointless? (I particularly like BOOL/Bool/eBool/boolean/bool/int conversions. Every program written by an orderly organization mandating typedefs is littered with that).
Of course in C++ we could make the type system more strict, by wrapping numbers in template class instantiations with overloaded operators and stuff. This means that you'll now get error messages of the form "class Number
Îmi place să folosesc tipurile stdint.h pentru definirea API-urilor de sistem, în special pentru că ele explică în mod explicit cât de mari sunt elementele. Înapoi în cele mai vechi timpuri ale sistemului de operare Palm OS, API-urile de sistem au fost definite folosind o grămadă de tipuri de tip "Word" și "SWord" care au fost moștenite de la Mac OS foarte clasic. Ei au făcut o curățare pentru a spune în schimb Int16 și a făcut API mai ușor pentru noii veniți să înțeleagă, mai ales cu ciudat probleme de 16 biți pointer pe acest sistem. Când proiectau Palm OS Cobalt, le-au schimbat din nou numele pentru a se potrivi cu numele lui stdint.h, făcând-o mai clară și reducând cantitatea de typedef-uri pe care trebuiau să le gestioneze.
Cred că standardele MISRA sugerează (necesită?) Utilizarea tipelor.
Din perspectivă personală, folosirea tippedefelor nu lasă nici o confuzie cu privire la mărimea (în biți / octeți) de anumite tipuri. Am văzut dezvoltatorii de plumb încercând ambele moduri de dezvoltare folosind tipuri standard, de ex. int și utilizând tipuri personalizate, de ex. UINT32.
În cazul în care codul nu este portabil, există beneficii reale mici în utilizarea typedefs, cu toate acestea , dacă, ca mine, atunci lucrați la ambele tipuri de software (mediu portabil și fix) poate fi utilă păstrarea unui standard și utilizarea tipurilor cutomizate. Cel puțin așa cum spui tu, programatorul este foarte conștient de cât de multă memorie folosesc. Un alt factor care trebuie luat în considerare este cât de sigur sunteți că codul nu va fi portat în alt mediu? Am văzut codul specific procesorului trebuie să fie tradus ca un angajat hardware a brusc a trebuit să schimbe o bord, aceasta nu este o situație frumos să fie în, dar datorită typedefs personalizat ar fi putut fi mult mai rău!
Dacă sistemele dvs. încorporate sunt într-un fel sistem critic de siguranță (sau similare), este foarte recomandat (dacă nu este necesar) .
După cum spune TK. , MISRA-C are o regulă (de consiliere) pentru a face acest lucru:
Regula 6.3 (consultativ): Tippedefele care indică dimensiunea și semnătura trebuie folosite în locul tipurilor numerice de bază.
(din MISRA-C 2004, este Regula # 13 (adv) din MISRA-C 1998)
Același lucru se aplică și în cazul C ++ în această zonă; de exemplu. Standarde de codare JSF C ++ :
Regulă AV 209 Se va crea un fișier UniversalTypes pentru a defini toate setările ndard tipuri pentru dezvoltatori de a utiliza. Tipurile includ: [uint16, int16, uint32_t etc]