איך אתה יכול לדעת את ההבדל בין ASCII בבינארי לאותו עשרוני בבינארי?


תשובה 1:

באופן כללי אתה לא יכול, לא על ידי הקטעים בלבד. לדוגמא, המספר 00111001 בבינארי: יכול להיות שהוא המספר 57, אך יתכן שהוא גם ספרת ASCII "9".

עם זאת, בפועל אתה יכול לעתים קרובות להבין את ההבדל. מכיוון שיהיה לך מושג מה הערך צריך להיות שאתה עובד איתו. שקול את פונקציית C הבאה, שיש בה באג בוהק:

הדפס int (int n) {char buf [1]; int i; i = 3 * n + 2; sprintf (buf, "% i \ n", i); מכניס (buf); להחזיר אני; }

זה מחשב עבור כל מספר שלם את הערך 3 * n + 2, זורק ערך זה לקונסולה ומחזיר את הערך כמספר שלם. עם זאת, ייתכן שתבחין בבדיקת פונקציה זו, שאם הקלט הוא, נניח 9, הוא מדפיס את התוצאה הנכונה 29 לקונסולה. אבל זה יחזיר את הערך הלא נכון, במקרה זה הערך 57. וזה עשוי לתת לך מושג מה קורה כאן, מכיוון שתבחין ש 57 הוא הייצוג ASCII של המספר 9, וזה במקרה הספרה האחרונה של התוצאה.

לאחר מכן אתה מבצע ניסויים ומגלה שזה נכון בכל פעם שהתוצאה היא מספר בן שתי ספרות. למשל, עם n = 5 התוצאה צריכה להיות 17, אך במקום זאת התוצאה היא 55, הייצוג של ASCII של הספרה "7".

וכשהתוצאה כוללת יותר משתי ספרות, התוצאה אפילו יותר רעה. לדוגמה, עם n = 50, התוצאה הנכונה 152 מושלכת על המסוף, אך ערך ההחזרה הוא 12853 בעשרוני, או 0x3235 בהקסדצימאלי. ייתכן שתבחין שזה הייצוג של ASCII של המחרוזת "25", או שתי הספרות האחרונות של התוצאה, בסדר הפוך!

אז מה קורה כאן? שימו לב שלמאגר התווים יש רק מקום לדמות יחידה! פונקציית sprintf () ב- C אינה בודקת אם יש חריפות מאגר, ולכן היא תכתוב בשמחה את הפלט שלה לזיכרון שמפנה אליו buf, ותחליף את הבתים מייד לאחר הבתים ששמורים ל- buf אם ה- buf קטן מדי. במקרה זה, מדובר בבתים השמורים למספר השלם i, והם מוחלפים. ומאחר שערך i משמש אז כערך ההחזרה של פונקציה זו, ערך ההחזרה יהיה שגוי.

נותרה רק שאלה אחת: מדוע ערך ההחזרה מכיל את הספרות האחרונות של ASCII של התוצאה, אך בסדר הפוך? זה קורה מכיוון (בהנחה שאתה עובד על מחשב) בתים של מספר שלם מאוחסנים "בדרך הלא נכונה". למשל, המספר השלם של 32 סיביות 0x12345678 נשמר כבתים 0x78 0x56 0x34 0x12 בזיכרון.

לכן, כאשר הקלט הוא n = 50, הספרה הראשונה של התוצאה תאוחסן ב- buf, ואילו הספרות השנייה והשלישית של התוצאה תגיע בסופו של דבר ל- i, שיהפוך, בתים, ל- 0x35 0x32 0x00 0x00. וזה מייצג את הערך 0x3235 = 12853 בעשרוני כאשר הוא מתפרש כמספר 32 סיביות.

כהערה אחרונה: אם היית מנסה לעשות זאת בפועל על המחשב שלך, התוצאות עשויות להיות שונות, מכיוון שההשפעות של סוג זה של תקלות תלויות מאוד בתפעול הפנימי של המכונה שלך ומהדר שלך. למשל, סמארטפון יאחסן לרוב את הביטים שלו בסדר הנכון, כך שתקבל מספר שונה כתוצאה מכך. וייתכן שהמהדר שלך שומר יותר מ- 1 בייט ל buf בגלל בעיות ביישור הזיכרון, או שהוא יכול לאחסן buf ואני להפך (אני קודם בזיכרון, ואז buf). לחלופין, זה עשוי לייעל את הרווח שלי רק על ידי שמירה על התוצאה בפנקס מעבד. במקרה כזה התוצאה תהיה נכונה אך משהו אחר בזיכרון ייפגם.

באופן כללי, אם תוכניות מכילות באגים כאלה, כל ההימורים הם לגבי מה שיקרה בפועל.


תשובה 2:

אם 48 הוא ייצוג ה- ASCII של המספר אפס, ו- 57 הוא הייצוג של ASCII של תשע, הרי שהנמבר הכי פחות משמעותי הוא הספרה המיוצגת בפועל:

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

או בפשטות; הפח 48 כדי לתת לך את המספר.