Πώς μπορείτε να πείτε τη διαφορά μεταξύ ASCII σε δυαδικό και το ίδιο δεκαδικό στο δυαδικό;


Απάντηση 1:

Σε γενικές γραμμές, δεν μπορείτε, όχι μόνο από τα bits. Για παράδειγμα, ο αριθμός 00111001 σε δυαδική μορφή: ίσως είναι ο αριθμός 57, αλλά μπορεί να είναι και ο αριθμός ASCII "9".

Τούτου λεχθέντος, στην πράξη μπορείτε να πείτε συχνά τη διαφορά. Επειδή θα έχετε κάποια ιδέα για το τι πρέπει να είναι η αξία με την οποία εργάζεστε. Εξετάστε την ακόλουθη συνάρτηση C, η οποία έχει ένα φαινομενικό σφάλμα σε αυτήν:

int εκτύπωση (int n) {char buf [1]; int i; i = 3 * η + 2. sprintf (buf, "% i \ n", i). βάζει (buf); επιστροφή i; }}

Υπολογίζει, για κάθε ακέραιο n, την τιμή 3 * n + 2, απορρίπτει αυτήν την τιμή στην κονσόλα και επιστρέφει την τιμή ως ακέραιο. Εντούτοις, ίσως παρατηρήσετε κατά τη δοκιμή αυτής της λειτουργίας, ότι εάν η είσοδος είναι, ας πούμε 9, εκτυπώνει το σωστό αποτέλεσμα 29 στην κονσόλα. Αλλά θα επιστρέψει λάθος αξία, στην περίπτωση αυτή την τιμή 57. Και αυτό μπορεί να σας δώσει κάποια ένδειξη για το τι συμβαίνει εδώ, καθώς θα παρατηρήσετε ότι 57 είναι η αναπαράσταση ASCII του αριθμού 9 και αυτό συμβαίνει να είναι το τελευταίο ψηφίο του αποτελέσματος.

Στη συνέχεια, κάνετε κάποιο πειραματισμό και διαπιστώστε ότι αυτό ισχύει όταν το αποτέλεσμα είναι ένας διψήφιος αριθμός. Για παράδειγμα, με n = 5 το αποτέλεσμα πρέπει να είναι 17, αλλά το αποτέλεσμα είναι 55, η αναπαράσταση ASCII του ψηφίου "7".

Και όταν το αποτέλεσμα έχει περισσότερα από 2 ψηφία, το αποτέλεσμα είναι ακόμη πιο περίπλοκο. Για παράδειγμα, με το n = 50, το σωστό αποτέλεσμα 152 απορρίπτεται στην κονσόλα, αλλά η τιμή επιστροφής είναι 12853 σε δεκαδικό ή 0x3235 σε δεκαεξαδική. Ίσως παρατηρήσετε ότι αυτή είναι η αναπαράσταση ASCII της συμβολοσειράς "25" ή των δύο τελευταίων ψηφίων του αποτελέσματος, με αντίστροφη σειρά!

Τι συμβαίνει εδώ; Παρατηρήστε ότι το buffer χαρακτήρων έχει μόνο χώρο για ένα μόνο χαρακτήρα! Η λειτουργία sprintf () στο C δεν ελέγχει για υπερβάσεις buffer, οπότε θα γράψει ευχαρίστως την έξοδο της στη μνήμη που υποδεικνύεται από το buf, αντικαθιστώντας τα bytes αμέσως μετά τα bytes που έχουν δεσμευτεί για το buf, εάν είναι υπερβολικά μικρό. Σε αυτή την περίπτωση, αυτά είναι τα bytes που προορίζονται για τον ακέραιο i, και αντικαθίστανται. Και δεδομένου ότι η τιμή του i χρησιμοποιείται στη συνέχεια ως τιμή επιστροφής αυτής της συνάρτησης, η τιμή επιστροφής θα είναι εσφαλμένη.

Παραμένει μόνο μία ερώτηση: γιατί η τιμή επιστροφής περιέχει τα τελευταία ψηφία ASCII του αποτελέσματος, αλλά με αντίστροφη σειρά; Αυτό συμβαίνει επειδή (αν υποθέσουμε ότι εργάζεστε σε έναν Η / Υ) τα bytes ενός ακέραιου αριθμού αποθηκεύονται "κατά λάθος". Για παράδειγμα, ο ακέραιος αριθμός 32-bit 0x12345678 αποθηκεύεται ως bytes 0x78 0x56 0x34 0x12 στη μνήμη.

Έτσι, όταν η είσοδος είναι n = 50, το πρώτο ψηφίο του αποτελέσματος θα αποθηκευτεί σε buf, ενώ το δεύτερο και τρίτο ψηφίο του αποτελέσματος θα καταλήξουν σε i, το οποίο στη συνέχεια θα γίνει, σε bytes, 0x35 0x32 0x00 0x00. Και αυτό αντιπροσωπεύει την τιμή 0x3235 = 12853 σε δεκαδικό όταν ερμηνεύεται ως αριθμός 32-bit.

Ως τελική σημείωση: αν προσπαθούσατε πραγματικά να το κάνετε αυτό στο μηχάνημά σας, τα αποτελέσματα μπορεί να είναι διαφορετικά, καθώς οι επιπτώσεις αυτού του τύπου σφαλμάτων εξαρτώνται σε μεγάλο βαθμό από την εσωτερική λειτουργία του μηχανήματος και του μεταγλωττιστή σας. Π.χ., ένα smartphone θα αποθηκεύει τα συχνά bytes του με τη σωστή σειρά, οπότε θα έχετε ως αποτέλεσμα έναν διαφορετικό αριθμό. Και ο μεταγλωττιστής σας μπορεί να διατηρεί περισσότερο από 1 byte για buf λόγω προβλημάτων ευθυγράμμισης μνήμης ή μπορεί να αποθηκεύει buf και i αντίστροφα (i πρώτα στη μνήμη, στη συνέχεια buf). Ή μπορεί να βελτιστοποιήσει i μακριά, διατηρώντας μόνο το αποτέλεσμα σε ένα μητρώο CPU. Σε αυτή την περίπτωση το αποτέλεσμα θα είναι σωστό, αλλά κάτι άλλο στη μνήμη θα είναι κατεστραμμένο.

Σε γενικές γραμμές, αν τα προγράμματα περιέχουν σφάλματα όπως αυτό, όλα τα στοιχήματα είναι ως προς το τι πραγματικά θα συμβεί.


Απάντηση 2:

Εάν το 48 είναι η αναπαράσταση ASCII του αριθμού μηδέν και 57 είναι η αναπαράσταση ASCII των εννέα, τότε το λιγότερο σημαντικό nibble είναι ο πραγματικός αριθμός που αντιπροσωπεύεται:

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 για να δώσετε τον αριθμό.