Làm thế nào bạn có thể cho biết sự khác biệt giữa ASCII trong nhị phân và cùng một số thập phân trong nhị phân?


Câu trả lời 1:

Nói chung, bạn không thể, không chỉ bởi các bit. Ví dụ, số 00111001 ở dạng nhị phân: nó cũng có thể là số 57, nhưng nó cũng có thể là chữ số ASCII Chữ 9 9.

Điều đó nói rằng, trong thực tế, bạn thường có thể nói sự khác biệt. Bởi vì bạn sẽ có một số ý tưởng về giá trị mà bạn nên làm việc với. Hãy xem xét hàm C sau đây, có một lỗi phát sáng trong đó:

int in (int n) {char buf [1]; int i; i = 3 * n + 2; chạy nước rút (buf, "% i \ n", i); đặt (buf); trả lại tôi; }

Nó tính toán, với mọi số nguyên n, giá trị 3 * n + 2, đưa giá trị này vào bàn điều khiển và trả về giá trị dưới dạng một số nguyên. Tuy nhiên, bạn có thể nhận thấy khi kiểm tra chức năng này, nếu đầu vào là 9, nó sẽ in kết quả chính xác 29 đến bàn điều khiển. Nhưng nó sẽ trả về giá trị sai, trong trường hợp này là giá trị 57. Và điều đó có thể cho bạn một số manh mối về những gì đang xảy ra ở đây, vì bạn sẽ nhận thấy rằng 57 là đại diện ASCII của số 9, và điều đó xảy ra chữ số cuối cùng của kết quả.

Sau đó, bạn thực hiện một số thử nghiệm và thấy rằng điều này đúng bất cứ khi nào kết quả là một số có 2 chữ số. Chẳng hạn, với n = 5, kết quả sẽ là 17, nhưng thay vào đó, kết quả là 55, biểu diễn ASCII của chữ số 7 7.

Và khi kết quả có nhiều hơn 2 chữ số, kết quả thậm chí còn lạ hơn. Chẳng hạn, với n = 50, kết quả chính xác 152 được kết xuất trên bàn điều khiển, nhưng giá trị trả về là 12853 ở dạng thập phân hoặc 0x3235 theo hệ thập lục phân. Bạn có thể nhận thấy rằng đó là đại diện ASCII của chuỗi Số 25, hoặc hai chữ số cuối của kết quả, theo thứ tự ngược lại!

Vậy thì chuyện gì đã xảy ra ở đây? Lưu ý rằng bộ đệm ký tự chỉ có chỗ cho một ký tự! Hàm sprintf () trong C không kiểm tra lỗi tràn bộ đệm, do đó, nó sẽ vui vẻ ghi đầu ra của nó vào bộ nhớ được trỏ bởi buf, ghi đè các byte ngay sau các byte dành riêng cho buf nếu buf quá nhỏ. Trong trường hợp này, đây là các byte dành riêng cho số nguyên i và chúng bị ghi đè. Và vì giá trị của i sau đó được sử dụng làm giá trị trả về của hàm này, nên giá trị trả về sẽ không chính xác.

Chỉ còn một câu hỏi: tại sao giá trị trả về chứa các chữ số ASCII cuối cùng của kết quả, nhưng theo thứ tự ngược lại? Điều đó xảy ra bởi vì (giả sử bạn đang làm việc trên PC) các byte của một số nguyên được lưu trữ sai cách xung quanh. Chẳng hạn, số nguyên 32 bit 0x12345678 được lưu dưới dạng byte 0x78 0x56 0x34 0x12 trong bộ nhớ.

Vì vậy, khi đầu vào là n = 50, chữ số đầu tiên của kết quả sẽ được lưu trong buf, trong khi chữ số thứ hai và thứ ba của kết quả sẽ kết thúc bằng i, sau đó sẽ trở thành, theo byte, 0x35 0x32 0x00 0x00. Và giá trị này biểu thị giá trị 0x3235 = 12853 theo số thập phân khi được hiểu là số 32 bit.

Lưu ý cuối cùng: nếu bạn thực sự thử điều này trên máy của mình, kết quả có thể khác, vì ảnh hưởng của loại lỗi này phụ thuộc rất nhiều vào hoạt động bên trong của máy và trình biên dịch của bạn. Ví dụ: điện thoại thông minh thường sẽ lưu trữ các byte của nó theo đúng thứ tự, do đó bạn sẽ nhận được một số khác. Và trình biên dịch của bạn có thể dự trữ nhiều hơn 1 byte cho buf vì các vấn đề căn chỉnh bộ nhớ hoặc nó có thể lưu trữ buf và i theo cách khác (đầu tiên là trong bộ nhớ, sau đó là buf). Hoặc nó có thể tối ưu hóa tôi đi bằng cách chỉ giữ kết quả trong một thanh ghi CPU. Trong trường hợp đó, kết quả sẽ đúng nhưng một cái gì đó khác trong bộ nhớ sẽ bị hỏng.

Nói chung, nếu các chương trình có lỗi như thế này, tất cả các cược là về những gì sẽ thực sự xảy ra.


Câu trả lời 2:

Nếu 48 là đại diện ASCII của số 0 và 57 là đại diện ASCII của chín, thì nibble ít quan trọng nhất là chữ số thực tế được biểu thị:

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

hoặc đơn giản; trừ 48 để cho bạn số.