როგორ შეგიძლიათ თქვათ განსხვავება ASCII- ს შორის ბინარულ და იგივე ათეულში ბინარულში?


პასუხი 1:

ზოგადად, თქვენ არ შეგიძლიათ, არა მხოლოდ ბიტების საშუალებით. მაგალითად, რიცხვი 00111001 ორობითი ფორმით: ეს შეიძლება იყოს ნომერი 57, მაგრამ ეს ასევე შეიძლება იყოს ASCII ნომერი "9".

თუმცა, პრაქტიკაში, ხშირად ხედავთ განსხვავებას. იმის გამო, რომ გაცნობიერებული გაქვთ, რა ღირებულებასთან უნდა იმუშაოთ. განვიხილოთ შემდეგი C ფუნქცია, რომელიც შეიცავს უხეშ შეცდომას:

int print (int n) {char buf [1]; მე; i = 3 * n + 2; sprintf (buf, "% i \ n", i); კომპლექტი (buf); დააბრუნე მე; }

იგი ითვლის 3 * n + 2 მნიშვნელობას თითოეული მთელი n- ისთვის, ამ მნიშვნელობას გამოაქვს კონსოლში და მნიშვნელობას უბრუნებს მთლიან რიცხვზე. ამასთან, ამ მახასიათებლის შესამოწმებლად, შეიძლება აღმოაჩენთ, რომ თუ 9 – ზე შეიყვანთ, სწორი შედეგი 29 იბეჭდება კონსოლზე. თუმცა, არასწორი მნიშვნელობა დაუბრუნდა, ამ შემთხვევაში მნიშვნელობა 57. და ამან შეიძლება მოგცეთ იმის მითითება, თუ რა ხდება აქ, რადგან თქვენ ნახავთ, რომ 57 არის ASCII 9-ის ნომრის წარმომადგენლობა და ეს ხდება ბოლო ციფრი. შედეგი.

შემდეგ ექსპერიმენტი და აღმოაჩენთ, რომ ეს ასეა, როდესაც შედეგი ორნიშნა რიცხვია. მაგალითად, n = 5-ით, შედეგი უნდა იყოს 17, მაგრამ სამაგიეროდ შედეგი არის 55, ASCII- ის ასახვა ნომერი "7".

და თუ შედეგს აქვს 2 – ზე მეტი ციფრი, შედეგიც უცხოა. მაგალითად, n = 50-ით, სწორი შედეგი 152 გამოდის კონსოლზე, მაგრამ დაბრუნების მნიშვნელობა არის 12853 ათობითი რიცხვში ან 0x3235 in hexadecimal რიცხვში. თქვენ აღმოაჩენთ, რომ ეს არის ASCII სიმებიანი სტრიქონი "25" ან შედეგის ბოლო ორი ციფრი საპირისპირო მიზნით!

რა ხდება აქ? გაითვალისწინეთ, რომ პერსონაჟების ბუფერი მხოლოდ ადგილს გთავაზობთ ერთი პერსონაჟისთვის! Sprintf () ფუნქცია C– ში არ შეამოწმებს ბუფერული გადინებების გამო, ასე რომ, მას მოსწონთ ჩაწერის მეხსიერებაზე მითითებული მეხსიერების დაწერა და ბაიტი ანაბეჭდება 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). ან მას შეუძლია ოპტიმიზაცია მოშორებით, მხოლოდ შედეგის შენახვით, CPU რეესტრში. ამ შემთხვევაში შედეგი სწორია, მაგრამ მეხსიერებაში რაღაც სხვაა კორუმპირებული.

თუ პროგრამები შეიცავს ასეთ შეცდომებს, ყველა ფსონი დაფუძნებულია იმაზე, თუ რა მოხდება რეალურად.


პასუხი 2:

თუ 48 არის ASCII ნულოვანი რიცხვის 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 ნომრის მისაღებად.