Hvordan kan du fortelle forskjellen mellom ASCII i binær og samme desimal i binær?


Svar 1:

Generelt kan du ikke, ikke av bitene alene. For eksempel tallet 00111001 i binær: det kan godt være tallet 57, men det kan også være ASCII-sifferet “9”.

Når det er sagt, i praksis kan du ofte fortelle forskjellen. Fordi du vil ha en anelse om hva verdien skal være at du jobber med. Tenk på følgende C-funksjon, som har en blendende feil i seg:

int print (int n) {char buf [1]; int i; i = 3 * n + 2; sprintf (buf, "% i \ n", i); opsjoner (buf); return i; }

Det beregner, for hvert heltall n, verdien 3 * n + 2, dumper denne verdien til konsollen og returnerer verdien som et heltall. Imidlertid vil du kanskje legge merke til når du tester denne funksjonen, at hvis inngangen er, si 9, skriver den ut riktig resultat 29 til konsollen. Men det vil returnere feil verdi, i dette tilfellet verdien 57. Og det kan gi deg en anelse om hva som skjer her, da du vil legge merke til at 57 er ASCII-representasjonen av tallet 9, og det skjer det siste sifferet i resultatet.

Så gjør du litt eksperimentering, og finner ut at dette stemmer når resultatet er et tosifret tall. For eksempel, med n = 5, bør resultatet være 17, men i stedet er resultatet 55, ASCII-representasjonen av sifferet "7".

Og når resultatet har mer enn to sifre, er resultatet enda mer rart. For eksempel, med n = 50, blir riktig resultat 152 dumpet på konsollen, men returverdien er 12853 i desimal, eller 0x3235 i heksadesimal. Du vil kanskje merke at det er ASCII-representasjonen av strengen “25”, eller de to siste sifrene i resultatet, i omvendt rekkefølge!

Så, hva skjer her? Legg merke til at karakterbufferen bare har plass til en enkelt karakter! Sprintf () -funksjonen i C sjekker ikke for bufferoverskridelser, så den vil gjerne skrive utdataene til minnet som er peket på av buf, og overskrive byteene umiddelbart etter bytene som er reservert for buf hvis buf er for liten. I dette tilfellet er dette byte som er reservert for heltallet i, og de blir overskrevet. Og siden verdien av i deretter blir brukt som returverdien for denne funksjonen, vil returverdien være feil.

Bare ett spørsmål gjenstår: hvorfor inneholder returverdien de siste ASCII-sifrene i resultatet, men i omvendt rekkefølge? Det skjer fordi (forutsatt at du jobber på en PC) bytene til et helt tall lagres "feil vei". For eksempel blir 32-biters heltall 0x12345678 lagret som byte 0x78 0x56 0x34 0x12 i minnet.

Så når inngangen er n = 50, vil det første sifferet i resultatet bli lagret i buf, mens det andre og tredje siffer i resultatet havner i i, som da blir, i byte, 0x35 0x32 0x00 0x00. Og dette representerer verdien 0x3235 = 12853 i desimal når den tolkes som et 32-bits tall.

Som en siste merknad: Hvis du faktisk skulle prøve dette på maskinen din, kan resultatene godt være forskjellige, siden effekten av denne typen feil er sterkt avhengig av maskinens og kompilatorens indre virkemåte. F.eks. Vil en smarttelefon ofte lagre byteene sine i riktig rekkefølge, slik at du får et annet nummer som et resultat. Og kompilatoren din kan godt reservere mer enn 1 byte for buf på grunn av problemer med minnejustering, eller den kan lagre buf og jeg omvendt (jeg først i minnet, deretter buf). Eller det kan optimalisere jeg unna ved bare å holde resultatet i et CPU-register. I så fall vil resultatet være riktig, men noe annet i minnet vil bli ødelagt.

Generelt, hvis programmer inneholder feil som dette, gjelder alle spill hva som faktisk vil skje.


Svar 2:

Hvis 48 er ASCII-representasjonen av tallet null, og 57 er ASCII-representasjonen av ni, er den minst betydelige nibble det faktiske sifferet som er representert:

0000 0000-0011 0000 = 32 + 16 + 0 = 48

0000 0001-0011 0001

0000 0010-0011 0010

0000 0011-0011 0011

0000 0100-0011 0100

0000 0101-0011 0101

0000 0110-0011 0110

0000 0111-0011 0111

0000 1000-0011 1000

0000 1001-0011 1001 = 32 + 16 + 8 + 1 = 57

eller ganske enkelt; trekke fra 48 for å gi deg tallet.