Magiskt nummer (programmering)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 10 december 2019; kontroller kräver 10 redigeringar .

Begreppet " magiskt nummer " i programmering har tre betydelser:

Datasignatur

Ett magiskt tal , eller signatur , är ett heltal eller en textkonstant som används för att unikt identifiera en resurs eller data . En sådan siffra i sig har ingen betydelse och kan orsaka förvirring om den förekommer i programkoden utan lämplig kontext eller kommentar , medan ett försök att ändra det till ett annat, till och med nära i värde, kan leda till helt oförutsägbara konsekvenser. Av denna anledning har sådana siffror ironiskt nog kallats magiska siffror . För närvarande är detta namn fast förankrat som en term . Till exempel börjar alla kompilerade Java - språkklasser med ett hexadecimalt "magiskt tal" 0xCAFEBABE. Det andra välkända exemplet är att alla körbara Microsoft Windows-filer med filtillägget .exe börjar med en sekvens av byte 0x4D5A(vilket motsvarar ASCII - tecknen MZ  - initialerna för Mark Zbikowski , en av skaparna av MS-DOS ). Ett mindre känt exempel är den oinitierade pekaren i Microsoft Visual C++ (sedan 2005 års version av Microsoft Visual Studio), som i felsökningsläge är 0xDEADBEEF.

På UNIX-liknande operativsystem bestäms typen av en fil vanligtvis av filens signatur, oavsett dess namntillägg. De tillhandahåller ett standardverktyg för att tolka filsignaturen file.

Dålig programmeringsövning

Dessutom är "magiska siffror" en dålig programmeringspraxis när ett numeriskt värde förekommer i källtexten och dess betydelse inte är uppenbar. Till exempel skulle ett utdrag som detta, skrivet i Java , vara dåligt:

drawSprite ( 53 , 320 , 240 );

Det är svårt för någon som inte har skrivit ett program att förstå vad 53, 320 eller 240 är. Men om den här koden skrivs om faller allt på plats.

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 );

Nu är det klart: den här koden visar en sprite i mitten av skärmen  - siktets hårkors. I de flesta programmeringsspråk kommer alla värden som används för sådana konstanter att beräknas vid kompilering och ersättas på de platser där värdena används ( konstant veck ). Därför försämrar inte en sådan ändring av källtexten programmets prestanda.

Dessutom är magiska siffror en potentiell källa till fel i programmet:

  • Om samma magiska siffra används mer än en gång i ett program (eller potentiellt skulle kunna användas), kommer en ändring av det att kräva att varje förekomst redigeras (istället för att bara redigera värdet på den namngivna konstanten). Om inte alla förekomster korrigeras kommer minst ett fel att uppstå.
  • I åtminstone en av händelserna kan det magiska numret vara felstavat initialt, och detta är ganska svårt att upptäcka.
  • Det magiska numret kan bero på en implicit parameter eller ett annat magiskt tal. Om dessa beroenden, som inte uttryckligen identifierats, inte är uppfyllda, kommer minst ett fel att inträffa.
  • När du ändrar förekomster av ett magiskt nummer är det möjligt att felaktigt ändra ett annat magiskt nummer som är oberoende men har samma numeriska värde.

Magiska siffror och plattformsoberoende

Ibland skadar magiska siffror plattformsoberoende kod [1] . Poängen är att i C i 32-bitars och 64-bitars operativsystem är storleken på typer char, shortoch garanterad long long, medan storleken på int, long, size_toch ptrdiff_tkan variera (för de två första, beroende på kompilatorutvecklarnas preferenser, för de två sista, beroende på bitdjupet i målsystemet). I gammal eller dåligt skriven kod kan det finnas "magiska siffror" som indikerar storleken på en typ - när man flyttar till maskiner med ett annat bitdjup kan de leda till subtila fel.

Till exempel:

const size_t NUMBER_OF_ELEMENTS = 10 ; lång a [ NUMBER_OF_ELEMENTS ]; memset ( a , 0 , 10 * 4 ); // fel - lång antas vara 4 byte, använder det magiska antalet element memset ( a , 0 , NUMBER_OF_ELEMENTS * 4 ); // fel - lång antas vara 4 byte memset ( a , 0 , NUMBER_OF_ELEMENTS * storleken på ( lång )); // inte helt korrekt - duplicering av typnamnet (om typen ändras måste du ändra här också) memset ( a , 0 , NUMBER_OF_ELEMENTS * sizeof ( a [ 0 ])); // korrekt, optimal för dynamiska arrayer av memset som inte är noll ( a , 0 , sizeof ( a )); // korrekt, optimal för statiska arrayer

Siffror som inte är magiska

Alla tal behöver inte omvandlas till konstanter. Till exempel, kod i Delphi :

för i := 0 för att räkna - 1 gör ...

Innebörden av siffrorna 0 och 1 är tydlig och ingen ytterligare förklaring behövs.

Se även

Anteckningar

  1. 20 fallgropar med att porta C++-kod till en 64-bitars plattform . Hämtad 31 oktober 2008. Arkiverad från originalet 15 augusti 2010.