ທ່ານສາມາດບອກຄວາມແຕກຕ່າງລະຫວ່າງ ASCII ໃນຖານສອງແລະອັດຕານິຍົມໃນຖານສອງໄດ້ແນວໃດ?


ຕອບ 1:

ໂດຍທົ່ວໄປ, ທ່ານບໍ່ສາມາດ, ບໍ່ພຽງແຕ່ຜ່ານບິດ. ຕົວຢ່າງ, ໝາຍ ເລກ 00111001 ໃນຮູບແບບຖານສອງ: ມັນອາດຈະແມ່ນເລກ 57, ແຕ່ມັນຍັງອາດແມ່ນຕົວເລກ ASCII "9".

ໃນການປະຕິບັດຕົວຈິງ, ທ່ານມັກຈະເຫັນຄວາມແຕກຕ່າງ. ເພາະວ່າທ່ານມີຄວາມຄິດທີ່ວ່າທ່ານຄວນເຮັດວຽກກັບຄຸນຄ່າຫຍັງ. ພິຈາລະນາຟັງຊັນ C ຕໍ່ໄປນີ້, ເຊິ່ງມີຂໍ້ຜິດພາດທີ່ບໍ່ແຈ້ງ:

int print (int n) {char buf [1]; int i; i = 3 * n + 2; sprintf (buf, "% i \ n", ຂ້ອຍ); ຊຸດ (buf); ກັບຄືນ i; }}

ມັນຈະຄິດໄລ່ມູນຄ່າ 3 * n + 2 ສຳ ລັບແຕ່ລະເລກ integer n, ສົ່ງຜົນໃຫ້ຄ່ານີ້ກັບ console ແລະສົ່ງຄືນຄ່າດັ່ງທີ່ເປັນເລກເຕັມ. ເຖິງຢ່າງໃດກໍ່ຕາມ, ເມື່ອທົດສອບຄຸນລັກສະນະນີ້, ທ່ານອາດຈະພົບວ່າຖ້າທ່ານໃສ່ເລກ 9, ຕົວຢ່າງ, ຜົນທີ່ຖືກຕ້ອງ 29 ຈະຖືກພິມຢູ່ເທິງ console. ເຖິງຢ່າງໃດກໍ່ຕາມ, ມູນຄ່າທີ່ບໍ່ຖືກຕ້ອງຖືກສົ່ງຄືນ, ໃນກໍລະນີນີ້ແມ່ນມູນຄ່າ 57. ແລະທີ່ສາມາດໃຫ້ທ່ານສະແດງເຖິງສິ່ງທີ່ ກຳ ລັງເກີດຂື້ນຢູ່ນີ້, ເພາະວ່າທ່ານຈະເຫັນວ່າ 57 ແມ່ນຕົວແທນຂອງ ASCII ຂອງເລກ 9 ແລະນີ້ກໍ່ຈະເປັນຕົວເລກສຸດທ້າຍ ຂອງຜົນໄດ້ຮັບ.

ຈາກນັ້ນທ່ານທົດລອງແລະພົບວ່ານີ້ແມ່ນຄວາມຈິງທຸກຄັ້ງທີ່ຜົນໄດ້ຮັບແມ່ນຕົວເລກສອງຕົວເລກ. ຍົກຕົວຢ່າງ, ດ້ວຍ n = 5, ຜົນໄດ້ຮັບຄວນຈະເປັນ 17, ແຕ່ແທນທີ່ຜົນໄດ້ຮັບແມ່ນ 55, ຕົວແທນ ASCII ຂອງຕົວເລກ "7".

ແລະຖ້າຜົນໄດ້ຮັບມີຫລາຍກວ່າ 2 ຕົວເລກ, ຜົນໄດ້ຮັບກໍ່ແມ່ນຄົນແປກ ໜ້າ. ຍົກຕົວຢ່າງ, ດ້ວຍ n = 50, ຜົນທີ່ຖືກຕ້ອງ 152 ແມ່ນຜົນຜະລິດຢູ່ເທິງຄອນໂຊນ, ແຕ່ວ່າມູນຄ່າການກັບມາແມ່ນ 12853 ໃນ ຈຳ ນວນທົດສະນິຍົມຫລື 0x3235 ໃນ ຈຳ ນວນ hexadecimal. ທ່ານອາດຈະພົບວ່ານີ້ແມ່ນຕົວແທນ ASCII ຂອງສາຍສະຕິງ "25" ຫຼືສອງຕົວເລກສຸດທ້າຍຂອງຜົນໄດ້ຮັບໃນການສັ່ງຊື້ຄືນ ໃໝ່!

ດັ່ງນັ້ນມີຫຍັງເກີດຂື້ນຢູ່ນີ້? ໃຫ້ສັງເກດວ່າ buffer ລັກສະນະພຽງແຕ່ສະຫນອງພື້ນທີ່ສໍາລັບຕົວອັກສອນດຽວ! ຟັງຊັ່ນ sprintf () ໃນ C ບໍ່ໄດ້ກວດສອບການໄຫລວຽນຂອງ buffer, ດັ່ງນັ້ນມັນມັກຂຽນຜົນຜະລິດຂອງມັນໃສ່ຫນ່ວຍຄວາມ ຈຳ ທີ່ຊີ້ໃຫ້ເຫັນໂດຍ buf, ແລະຂຽນທັບ bytes ທັນທີຫຼັງຈາກ bytes ທີ່ສະຫງວນໄວ້ ສຳ ລັບ buf ຖ້າ buf ຍັງນ້ອຍເກີນໄປ. ໃນກໍລະນີນີ້, ເຫຼົ່ານີ້ແມ່ນໄບຕ໌ທີ່ສະຫງວນໄວ້ ສຳ ລັບເລກເຕັມ i ແລະພວກມັນຖືກຂຽນທັບ. ແລະເນື່ອງຈາກວ່າມູນຄ່າຂອງ i ຫຼັງຈາກນັ້ນຖືກ ນຳ ໃຊ້ເປັນຄ່າຜົນຕອບແທນຂອງ ໜ້າ ທີ່ນີ້, ມູນຄ່າການກັບຄືນແມ່ນຜິດພາດ.

ມີພຽງແຕ່ ຄຳ ຖາມ ໜຶ່ງ ເທົ່ານັ້ນ: ເປັນຫຍັງມູນຄ່າການສົ່ງຄືນຈຶ່ງມີຕົວເລກ ASCII ສຸດທ້າຍຂອງຜົນໄດ້ຮັບ, ແຕ່ເປັນການຕາມ ລຳ ດັບ? ນີ້ແມ່ນຍ້ອນວ່າ (ສົມມຸດວ່າທ່ານ ກຳ ລັງເຮັດວຽກຢູ່ໃນຄອມພີວເຕີ້) ໄບຕ໌ຂອງໂຕເລກແມ່ນຖືກເກັບໄວ້ເປັນ "ທາງທີ່ບໍ່ຖືກຕ້ອງ". ຍົກຕົວຢ່າງ, ເລກເຕັມ 32 ບິດ 0x12345678 ຖືກເກັບໄວ້ໃນຫນ່ວຍຄວາມ ຈຳ ເປັນໄບຕ໌ 0x78 0x56 0x34 0x12.

ສະນັ້ນຖ້າການປ້ອນຂໍ້ມູນແມ່ນ n = 50, ຕົວເລກ ທຳ ອິດຂອງຜົນໄດ້ຮັບແມ່ນເກັບໄວ້ໃນ buf, ໃນຂະນະທີ່ຕົວເລກທີສອງແລະສາມຂອງຜົນໄດ້ຮັບຈະສິ້ນສຸດລົງໃນ i, ເຊິ່ງຕໍ່ມາຈະກາຍເປັນ bytes 0x35 0x32 0x00 0x00. ແລະນີ້ ໝາຍ ເຖິງມູນຄ່າ 0x3235 = 12853 ໃນອັດຕານິຍົມຖ້າມັນຖືກຕີຄວາມ ໝາຍ ເປັນເລກ 32 ບິດ.

ເປັນຂໍ້ສັງເກດສຸດທ້າຍ, ຖ້າທ່ານທົດລອງໃຊ້ຕົວຈິງໃນຄອມພິວເຕີຂອງທ່ານ, ຜົນໄດ້ຮັບອາດຈະແຕກຕ່າງກັນ, ເພາະວ່າຜົນກະທົບຂອງປະເພດຂໍ້ຜິດພາດເຫລົ່ານີ້ແມ່ນຂື້ນກັບຄອມພິວເຕີພາຍໃນແລະຜູ້ລວບລວມຂໍ້ມູນຂອງທ່ານ. ຍົກຕົວຢ່າງ, ໂທລະສັບສະຫຼາດມັກຈະເກັບຮັກສາໄບຂອງມັນຢູ່ໃນຄໍາສັ່ງທີ່ຖືກຕ້ອງເພື່ອໃຫ້ທ່ານໄດ້ຈໍານວນທີ່ແຕກຕ່າງກັນ. ແລະຜູ້ລວບລວມຂໍ້ມູນຂອງທ່ານອາດຈະສະຫງວນຫຼາຍກວ່າ 1 ໄບຕ໌ ສຳ ລັບ buf ເນື່ອງຈາກບັນຫາຄວາມສອດຄ່ອງຂອງຄວາມ ຈຳ, ຫຼືມັນອາດຈະເກັບຮັກສາ buf ແລະ i ໃນທາງກັບກັນ (ຂ້ອຍ ທຳ ອິດໃນ ໜ່ວຍ ຄວາມ ຈຳ, ຫຼັງຈາກນັ້ນກໍ່ສ້າງ). ຫຼືມັນສາມາດເພີ່ມປະສິດທິພາບໃຫ້ດີຂື້ນໂດຍພຽງແຕ່ເກັບຜົນໄດ້ຮັບໃນການລົງທະບຽນ CPU. ໃນກໍລະນີນີ້, ຜົນໄດ້ຮັບແມ່ນຖືກຕ້ອງ, ແຕ່ວ່າບາງສິ່ງບາງຢ່າງອື່ນໃນຄວາມຊົງຈໍາແມ່ນເສຍຫາຍ.

ຖ້າບັນດາໂປແກຼມບັນຈຸຂໍ້ຜິດພາດດັ່ງກ່າວ, ການວາງເດີມພັນທັງ ໝົດ ແມ່ນອີງໃສ່ສິ່ງທີ່ຈະເກີດຂື້ນຈິງ.


ຕອບ 2:

ຖ້າ 48 ແມ່ນຕົວແທນ ASCII ຂອງເລກສູນແລະ 57 ແມ່ນຕົວແທນ ASCII ຂອງ ຈຳ ນວນເກົ້າ, ຕົວເລກທີ່ບໍ່ມີຄວາມ ໝາຍ ໜ້ອຍ ທີ່ສຸດແມ່ນຕົວເລກຕົວຈິງ:

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

0000 0001-0011 0001

0000 00.1010.101111-101110 101010

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 ເພື່ອເອົາເລກ.