Număr magic (programare)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 10 decembrie 2019; verificările necesită 10 modificări .

Conceptul de „ număr magic ” în programare are trei semnificații:

Semnătura datelor

Un număr magic , sau semnătură , este un număr întreg sau constantă de text folosită pentru a identifica în mod unic o resursă sau date . Un astfel de număr în sine nu are nicio semnificație și poate provoca nedumerire dacă apare în codul programului fără contextul sau comentariul adecvat , în timp ce o încercare de a-l schimba cu altul, chiar apropiat ca valoare, poate duce la consecințe absolut imprevizibile. Din acest motiv, astfel de numere au fost numite în mod ironic numere magice . În prezent, acest nume este ferm înrădăcinat ca termen . De exemplu, orice clasă de limbaj Java compilată începe cu un „număr magic” hexazecimal0xCAFEBABE . Al doilea exemplu binecunoscut este că orice fișier executabil Microsoft Windows cu extensia .exe începe cu o secvență de octeți 0x4D5A(care corespunde caracterelor ASCII MZ  - inițialele lui Mark Zbikowski , unul dintre creatorii MS-DOS ). Un exemplu mai puțin cunoscut este indicatorul neinițializat din Microsoft Visual C++ (din versiunea din 2005 a Microsoft Visual Studio), care în modul de depanare este 0xDEADBEEF.

Pe sistemele de operare asemănătoare UNIX, tipul unui fișier este de obicei determinat de semnătura fișierului, indiferent de extensia numelui acestuia. Ele oferă un utilitar standard pentru a interpreta semnătura fișierului file.

Practică proastă de programare

De asemenea, „numere magice” este o practică proastă de programare atunci când o valoare numerică apare în textul sursă și semnificația acesteia nu este evidentă. De exemplu, un fragment ca acesta, scris în Java , ar fi rău:

drawSprite ( 53 , 320 , 240 );

Este dificil pentru cineva care nu a scris un program să înțeleagă ce este 53, 320 sau 240. Dar dacă acest cod este rescris, totul cade la locul său.

final int SCREEN_WIDTH = 640 ; final int SCREEN_HEIGHT = 480 ; final int SCREEN_X_CENTER = SCREEN_WIDTH / 2 ; final int SCREEN_Y_CENTER = SCREEN_HEIGHT / 2 ; final int SPRITE_CROSSHAIR = 53 ; ... drawSprite ( SPRITE_CROSSHAIR , SCREEN_X_CENTER , SCREEN_Y_CENTER );

Acum este clar: acest cod afișează un sprite în centrul ecranului  - punctul încrucișat al vederii. În majoritatea limbajelor de programare, toate valorile utilizate pentru astfel de constante vor fi calculate în timpul compilării și înlocuite în locurile în care sunt utilizate valorile ( pliere constantă ). Prin urmare, o astfel de modificare a textului sursă nu afectează performanța programului.

În plus, numerele magice sunt o sursă potențială de erori în program:

  • Dacă același număr magic este folosit de mai multe ori într-un program (sau ar putea fi utilizat), atunci modificarea acestuia va necesita editarea fiecărei apariții (în loc să editați doar valoarea constantei numite). Dacă nu toate aparițiile sunt corectate, va apărea cel puțin o eroare.
  • În cel puțin una dintre apariții, numărul magic poate fi scris greșit inițial, iar acest lucru este destul de dificil de detectat.
  • Numărul magic poate depinde de un parametru implicit sau de un alt număr magic. Dacă aceste dependențe, neidentificate explicit, nu sunt satisfăcute, va apărea cel puțin o eroare.
  • Când se modifică aparițiile unui număr magic, este posibil să se schimbe în mod eronat un alt număr magic care este independent, dar are aceeași valoare numerică.

Numere magice și multi-platformă

Uneori, numerele magice rănesc codul multiplatform [1] . Ideea este că în C în sistemele de operare pe 32 și 64 de biți, dimensiunea tipurilor char, shortși este garantată long long, în timp ce dimensiunea int, long, size_tși ptrdiff_tpoate varia (pentru primele două, în funcție de preferințele dezvoltatorilor de compilatoare, pt. ultimele două, în funcție de adâncimea de biți a sistemului țintă). În codul vechi sau prost scris, pot exista „numere magice” care indică dimensiunea unui tip - atunci când treceți la mașini cu o adâncime de biți diferită, acestea pot duce la erori subtile.

De exemplu:

const size_t NUMBER_OF_ELEMENTS = 10 ; lung a [ NUMBER_OF_ELEMENTS ]; memset ( a , 0 , 10 * 4 ); // greșit - se presupune că lung este de 4 octeți, folosește numărul magic de elemente memset ( a , 0 , NUMBER_OF_ELEMENTS * 4 ); // greșit - se presupune că lung este de 4 octeți memset ( a , 0 , NUMBER_OF_ELEMENTS * sizeof ( long )); // nu este complet corectă - duplicarea numelui tipului (dacă tipul se schimbă, va trebui să schimbați și aici) memset ( a , 0 , NUMBER_OF_ELEMENTS * sizeof ( a [ 0 ])); // corect, optim pentru matrice dinamice de dimensiune diferită de zero memset ( a , 0 , sizeof ( a )); // corect, optim pentru matrice statice

Numerele care nu sunt magice

Nu toate numerele trebuie convertite în constante. De exemplu, cod în Delphi :

pentru i := 0 to Count - 1 do ...

Semnificația numerelor 0 și 1 este clară și nu este nevoie de o explicație suplimentară.

Vezi și

Note

  1. 20 de capcane ale portarii codului C++ pe o platformă pe 64 de biți . Consultat la 31 octombrie 2008. Arhivat din original la 15 august 2010.